@nlabs/lex 1.49.4 → 1.50.0

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.
Files changed (55) hide show
  1. package/.swcrc +35 -0
  2. package/README.md +43 -59
  3. package/__mocks__/chalk.js +19 -17
  4. package/config.json +32 -8
  5. package/examples/lex.config.js +110 -10
  6. package/index.cjs +1 -5
  7. package/lex.config.js +34 -7
  8. package/lib/Button.stories.js +99 -0
  9. package/lib/LexConfig.d.ts +60 -22
  10. package/lib/LexConfig.js +285 -244
  11. package/lib/commands/ai/ai.js +287 -288
  12. package/lib/commands/ai/index.js +8 -7
  13. package/lib/commands/build/build.d.ts +2 -2
  14. package/lib/commands/build/build.js +349 -458
  15. package/lib/commands/clean/clean.js +45 -33
  16. package/lib/commands/compile/compile.js +214 -227
  17. package/lib/commands/config/config.js +46 -42
  18. package/lib/commands/copy/copy.js +36 -35
  19. package/lib/commands/create/create.js +200 -121
  20. package/lib/commands/dev/dev.d.ts +2 -0
  21. package/lib/commands/dev/dev.js +259 -263
  22. package/lib/commands/init/init.js +108 -88
  23. package/lib/commands/link/link.js +18 -14
  24. package/lib/commands/lint/lint.js +735 -742
  25. package/lib/commands/migrate/migrate.js +49 -36
  26. package/lib/commands/publish/publish.js +116 -96
  27. package/lib/commands/serverless/serverless.js +611 -585
  28. package/lib/commands/storybook/storybook.js +242 -238
  29. package/lib/commands/test/test.d.ts +1 -1
  30. package/lib/commands/test/test.js +382 -394
  31. package/lib/commands/update/update.js +141 -120
  32. package/lib/commands/upgrade/upgrade.js +51 -44
  33. package/lib/commands/versions/versions.d.ts +1 -1
  34. package/lib/commands/versions/versions.js +36 -38
  35. package/lib/create/changelog.js +136 -125
  36. package/lib/index.js +40 -38
  37. package/lib/lex.js +95 -68
  38. package/lib/storybook/index.js +6 -1
  39. package/lib/test-react/index.js +7 -84
  40. package/lib/types.d.ts +1 -1
  41. package/lib/types.js +7 -1
  42. package/lib/utils/aiService.js +240 -227
  43. package/lib/utils/app.js +274 -273
  44. package/lib/utils/deepMerge.js +37 -23
  45. package/lib/utils/file.js +218 -215
  46. package/lib/utils/log.js +29 -27
  47. package/lib/utils/reactShim.js +7 -85
  48. package/lib/utils/translations.js +91 -65
  49. package/package.json +63 -64
  50. package/templates/typescript/DataLayer.js.txt +218 -0
  51. package/templates/typescript/DataLayer.test.js.txt +268 -0
  52. package/templates/typescript/DataLayer.test.ts.txt +269 -0
  53. package/templates/typescript/DataLayer.ts.txt +227 -0
  54. package/webpack.config.js +53 -26
  55. package/lib/commands/lint/autofix.d.ts +0 -2
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Copyright (c) 2018-Present, Nitrogen Labs, Inc.
3
+ * Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
4
+ */
5
+ import {APIGatewayProxyEvent, Context} from 'aws-lambda';
6
+
7
+ import {DataLayer, handler} from './DataLayer.js';
8
+
9
+ describe('DataLayer', () => {
10
+ let dataLayer: DataLayer;
11
+ let mockContext: Context;
12
+
13
+ beforeEach(() => {
14
+ dataLayer = new DataLayer({
15
+ tableName: 'test-table',
16
+ region: 'us-east-1'
17
+ });
18
+
19
+ mockContext = {
20
+ awsRequestId: 'test-request-id',
21
+ functionName: 'test-function',
22
+ functionVersion: '$LATEST',
23
+ getRemainingTimeInMillis: () => 30000,
24
+ invokedFunctionArn: 'arn:aws:lambda:us-east-1:123456789012:function:test-function',
25
+ logGroupName: '/aws/lambda/test-function',
26
+ logStreamName: 'test-log-stream',
27
+ memoryLimitInMB: '128'
28
+ } as Context;
29
+ });
30
+
31
+ describe('getItem', () => {
32
+ it('should get an item by ID', async () => {
33
+ const result = await dataLayer.getItem('test-id');
34
+
35
+ expect(result).toEqual({
36
+ id: 'test-id',
37
+ data: 'sample data',
38
+ timestamp: expect.any(String)
39
+ });
40
+ });
41
+ });
42
+
43
+ describe('createItem', () => {
44
+ it('should create a new item', async () => {
45
+ const itemData = {
46
+ name: 'Test Item',
47
+ description: 'A test item'
48
+ };
49
+
50
+ const result = await dataLayer.createItem(itemData);
51
+
52
+ expect(result).toEqual({
53
+ id: expect.stringMatching(/^item-\d+$/),
54
+ name: 'Test Item',
55
+ description: 'A test item',
56
+ createdAt: expect.any(String),
57
+ updatedAt: expect.any(String)
58
+ });
59
+ });
60
+
61
+ it('should create an item with custom ID', async () => {
62
+ const itemData = {
63
+ id: 'custom-id',
64
+ name: 'Test Item'
65
+ };
66
+
67
+ const result = await dataLayer.createItem(itemData);
68
+
69
+ expect(result.id).toBe('custom-id');
70
+ expect(result.name).toBe('Test Item');
71
+ });
72
+ });
73
+
74
+ describe('updateItem', () => {
75
+ it('should update an existing item', async () => {
76
+ const updateData = {
77
+ name: 'Updated Item',
78
+ description: 'Updated description'
79
+ };
80
+
81
+ const result = await dataLayer.updateItem('test-id', updateData);
82
+
83
+ expect(result).toEqual({
84
+ id: 'test-id',
85
+ name: 'Updated Item',
86
+ description: 'Updated description',
87
+ updatedAt: expect.any(String)
88
+ });
89
+ });
90
+ });
91
+
92
+ describe('deleteItem', () => {
93
+ it('should delete an item by ID', async () => {
94
+ const result = await dataLayer.deleteItem('test-id');
95
+
96
+ expect(result).toBe(true);
97
+ });
98
+ });
99
+
100
+ describe('listItems', () => {
101
+ it('should list items without filters', async () => {
102
+ const result = await dataLayer.listItems();
103
+
104
+ expect(Array.isArray(result)).toBe(true);
105
+ expect(result.length).toBeGreaterThan(0);
106
+ expect(result[0]).toHaveProperty('id');
107
+ expect(result[0]).toHaveProperty('data');
108
+ expect(result[0]).toHaveProperty('timestamp');
109
+ });
110
+
111
+ it('should list items with filters', async () => {
112
+ const filters = {
113
+ status: 'active'
114
+ };
115
+
116
+ const result = await dataLayer.listItems(filters);
117
+
118
+ expect(Array.isArray(result)).toBe(true);
119
+ });
120
+ });
121
+
122
+ describe('handleRequest', () => {
123
+ it('should handle GET request for single item', async () => {
124
+ const event: APIGatewayProxyEvent = {
125
+ httpMethod: 'GET',
126
+ pathParameters: {id: 'test-id'},
127
+ body: null,
128
+ queryStringParameters: null
129
+ } as APIGatewayProxyEvent;
130
+
131
+ const result = await dataLayer.handleRequest(event, mockContext);
132
+
133
+ expect(result.statusCode).toBe(200);
134
+ expect(result.headers['Content-Type']).toBe('application/json');
135
+ expect(result.headers['Access-Control-Allow-Origin']).toBe('*');
136
+
137
+ const body = JSON.parse(result.body);
138
+ expect(body.id).toBe('test-id');
139
+ });
140
+
141
+ it('should handle GET request for list items', async () => {
142
+ const event: APIGatewayProxyEvent = {
143
+ httpMethod: 'GET',
144
+ pathParameters: null,
145
+ body: null,
146
+ queryStringParameters: {status: 'active'}
147
+ } as APIGatewayProxyEvent;
148
+
149
+ const result = await dataLayer.handleRequest(event, mockContext);
150
+
151
+ expect(result.statusCode).toBe(200);
152
+ const body = JSON.parse(result.body);
153
+ expect(Array.isArray(body)).toBe(true);
154
+ });
155
+
156
+ it('should handle POST request', async () => {
157
+ const event: APIGatewayProxyEvent = {
158
+ httpMethod: 'POST',
159
+ pathParameters: null,
160
+ body: JSON.stringify({
161
+ name: 'New Item',
162
+ description: 'A new item'
163
+ }),
164
+ queryStringParameters: null
165
+ } as APIGatewayProxyEvent;
166
+
167
+ const result = await dataLayer.handleRequest(event, mockContext);
168
+
169
+ expect(result.statusCode).toBe(200);
170
+ const body = JSON.parse(result.body);
171
+ expect(body.name).toBe('New Item');
172
+ expect(body.description).toBe('A new item');
173
+ });
174
+
175
+ it('should handle PUT request', async () => {
176
+ const event: APIGatewayProxyEvent = {
177
+ httpMethod: 'PUT',
178
+ pathParameters: {id: 'test-id'},
179
+ body: JSON.stringify({
180
+ name: 'Updated Item'
181
+ }),
182
+ queryStringParameters: null
183
+ } as APIGatewayProxyEvent;
184
+
185
+ const result = await dataLayer.handleRequest(event, mockContext);
186
+
187
+ expect(result.statusCode).toBe(200);
188
+ const body = JSON.parse(result.body);
189
+ expect(body.id).toBe('test-id');
190
+ expect(body.name).toBe('Updated Item');
191
+ });
192
+
193
+ it('should handle DELETE request', async () => {
194
+ const event: APIGatewayProxyEvent = {
195
+ httpMethod: 'DELETE',
196
+ pathParameters: {id: 'test-id'},
197
+ body: null,
198
+ queryStringParameters: null
199
+ } as APIGatewayProxyEvent;
200
+
201
+ const result = await dataLayer.handleRequest(event, mockContext);
202
+
203
+ expect(result.statusCode).toBe(200);
204
+ const body = JSON.parse(result.body);
205
+ expect(body.message).toBe('Item deleted successfully');
206
+ });
207
+
208
+ it('should return 400 for PUT without ID', async () => {
209
+ const event: APIGatewayProxyEvent = {
210
+ httpMethod: 'PUT',
211
+ pathParameters: null,
212
+ body: JSON.stringify({name: 'Updated Item'}),
213
+ queryStringParameters: null
214
+ } as APIGatewayProxyEvent;
215
+
216
+ const result = await dataLayer.handleRequest(event, mockContext);
217
+
218
+ expect(result.statusCode).toBe(400);
219
+ const body = JSON.parse(result.body);
220
+ expect(body.error).toBe('ID is required for update operations');
221
+ });
222
+
223
+ it('should return 400 for DELETE without ID', async () => {
224
+ const event: APIGatewayProxyEvent = {
225
+ httpMethod: 'DELETE',
226
+ pathParameters: null,
227
+ body: null,
228
+ queryStringParameters: null
229
+ } as APIGatewayProxyEvent;
230
+
231
+ const result = await dataLayer.handleRequest(event, mockContext);
232
+
233
+ expect(result.statusCode).toBe(400);
234
+ const body = JSON.parse(result.body);
235
+ expect(body.error).toBe('ID is required for delete operations');
236
+ });
237
+
238
+ it('should return 405 for unsupported method', async () => {
239
+ const event: APIGatewayProxyEvent = {
240
+ httpMethod: 'OPTIONS',
241
+ pathParameters: null,
242
+ body: null,
243
+ queryStringParameters: null
244
+ } as APIGatewayProxyEvent;
245
+
246
+ const result = await dataLayer.handleRequest(event, mockContext);
247
+
248
+ expect(result.statusCode).toBe(405);
249
+ const body = JSON.parse(result.body);
250
+ expect(body.error).toBe('Method not allowed');
251
+ });
252
+ });
253
+
254
+ describe('handler function', () => {
255
+ it('should work as Lambda handler', async () => {
256
+ const event: APIGatewayProxyEvent = {
257
+ httpMethod: 'GET',
258
+ pathParameters: {id: 'test-id'},
259
+ body: null,
260
+ queryStringParameters: null
261
+ } as APIGatewayProxyEvent;
262
+
263
+ const result = await handler(event, mockContext);
264
+
265
+ expect(result.statusCode).toBe(200);
266
+ expect(result.headers['Content-Type']).toBe('application/json');
267
+ });
268
+ });
269
+ });
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Copyright (c) 2018-Present, Nitrogen Labs, Inc.
3
+ * Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
4
+ */
5
+ import {APIGatewayProxyEvent, APIGatewayProxyResult, Context} from 'aws-lambda';
6
+
7
+ export interface DataLayerOptions {
8
+ readonly tableName?: string;
9
+ readonly region?: string;
10
+ readonly endpoint?: string;
11
+ }
12
+
13
+ export class DataLayer {
14
+ private readonly options: DataLayerOptions;
15
+
16
+ constructor(options: DataLayerOptions = {}) {
17
+ this.options = {
18
+ tableName: process.env.TABLE_NAME || 'default-table',
19
+ region: process.env.AWS_REGION || 'us-east-1',
20
+ endpoint: process.env.DYNAMODB_ENDPOINT,
21
+ ...options
22
+ };
23
+ }
24
+
25
+ /**
26
+ * Get a single item by ID
27
+ */
28
+ async getItem(id: string): Promise<any> {
29
+ try {
30
+ // TODO: Implement DynamoDB getItem logic
31
+ console.log(`Getting item with ID: ${id}`);
32
+
33
+ // Example response structure
34
+ return {
35
+ id,
36
+ data: 'sample data',
37
+ timestamp: new Date().toISOString()
38
+ };
39
+ } catch (error) {
40
+ console.error('Error getting item:', error);
41
+ throw error;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Create a new item
47
+ */
48
+ async createItem(data: any): Promise<any> {
49
+ try {
50
+ // TODO: Implement DynamoDB putItem logic
51
+ console.log('Creating new item:', data);
52
+
53
+ const newItem = {
54
+ id: data.id || `item-${Date.now()}`,
55
+ ...data,
56
+ createdAt: new Date().toISOString(),
57
+ updatedAt: new Date().toISOString()
58
+ };
59
+
60
+ return newItem;
61
+ } catch (error) {
62
+ console.error('Error creating item:', error);
63
+ throw error;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Update an existing item
69
+ */
70
+ async updateItem(id: string, data: any): Promise<any> {
71
+ try {
72
+ // TODO: Implement DynamoDB updateItem logic
73
+ console.log(`Updating item ${id}:`, data);
74
+
75
+ const updatedItem = {
76
+ id,
77
+ ...data,
78
+ updatedAt: new Date().toISOString()
79
+ };
80
+
81
+ return updatedItem;
82
+ } catch (error) {
83
+ console.error('Error updating item:', error);
84
+ throw error;
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Delete an item by ID
90
+ */
91
+ async deleteItem(id: string): Promise<boolean> {
92
+ try {
93
+ // TODO: Implement DynamoDB deleteItem logic
94
+ console.log(`Deleting item with ID: ${id}`);
95
+
96
+ return true;
97
+ } catch (error) {
98
+ console.error('Error deleting item:', error);
99
+ throw error;
100
+ }
101
+ }
102
+
103
+ /**
104
+ * List items with optional filtering
105
+ */
106
+ async listItems(filters?: any): Promise<any[]> {
107
+ try {
108
+ // TODO: Implement DynamoDB scan/query logic
109
+ console.log('Listing items with filters:', filters);
110
+
111
+ // Example response
112
+ return [
113
+ {
114
+ id: 'item-1',
115
+ data: 'sample data 1',
116
+ timestamp: new Date().toISOString()
117
+ },
118
+ {
119
+ id: 'item-2',
120
+ data: 'sample data 2',
121
+ timestamp: new Date().toISOString()
122
+ }
123
+ ];
124
+ } catch (error) {
125
+ console.error('Error listing items:', error);
126
+ throw error;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Lambda handler for HTTP requests
132
+ */
133
+ async handleRequest(event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult> {
134
+ try {
135
+ const {httpMethod, pathParameters, body, queryStringParameters} = event;
136
+ const id = pathParameters?.id;
137
+
138
+ let result: any;
139
+
140
+ switch (httpMethod) {
141
+ case 'GET':
142
+ if (id) {
143
+ result = await this.getItem(id);
144
+ } else {
145
+ result = await this.listItems(queryStringParameters);
146
+ }
147
+ break;
148
+
149
+ case 'POST':
150
+ const createData = body ? JSON.parse(body) : {};
151
+ result = await this.createItem(createData);
152
+ break;
153
+
154
+ case 'PUT':
155
+ case 'PATCH':
156
+ if (!id) {
157
+ return {
158
+ statusCode: 400,
159
+ headers: {
160
+ 'Content-Type': 'application/json',
161
+ 'Access-Control-Allow-Origin': '*'
162
+ },
163
+ body: JSON.stringify({error: 'ID is required for update operations'})
164
+ };
165
+ }
166
+ const updateData = body ? JSON.parse(body) : {};
167
+ result = await this.updateItem(id, updateData);
168
+ break;
169
+
170
+ case 'DELETE':
171
+ if (!id) {
172
+ return {
173
+ statusCode: 400,
174
+ headers: {
175
+ 'Content-Type': 'application/json',
176
+ 'Access-Control-Allow-Origin': '*'
177
+ },
178
+ body: JSON.stringify({error: 'ID is required for delete operations'})
179
+ };
180
+ }
181
+ await this.deleteItem(id);
182
+ result = {message: 'Item deleted successfully'};
183
+ break;
184
+
185
+ default:
186
+ return {
187
+ statusCode: 405,
188
+ headers: {
189
+ 'Content-Type': 'application/json',
190
+ 'Access-Control-Allow-Origin': '*'
191
+ },
192
+ body: JSON.stringify({error: 'Method not allowed'})
193
+ };
194
+ }
195
+
196
+ return {
197
+ statusCode: 200,
198
+ headers: {
199
+ 'Content-Type': 'application/json',
200
+ 'Access-Control-Allow-Origin': '*'
201
+ },
202
+ body: JSON.stringify(result)
203
+ };
204
+
205
+ } catch (error) {
206
+ console.error('Handler error:', error);
207
+
208
+ return {
209
+ statusCode: 500,
210
+ headers: {
211
+ 'Content-Type': 'application/json',
212
+ 'Access-Control-Allow-Origin': '*'
213
+ },
214
+ body: JSON.stringify({
215
+ error: 'Internal server error',
216
+ message: error instanceof Error ? error.message : 'Unknown error'
217
+ })
218
+ };
219
+ }
220
+ }
221
+ }
222
+
223
+ // Export the handler function for Lambda
224
+ export const handler = async (event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult> => {
225
+ const dataLayer = new DataLayer();
226
+ return dataLayer.handleRequest(event, context);
227
+ };
package/webpack.config.js CHANGED
@@ -9,7 +9,7 @@ import CompressionWebpackPlugin from 'compression-webpack-plugin';
9
9
  import CopyWebpackPlugin from 'copy-webpack-plugin';
10
10
  import cssnano from 'cssnano';
11
11
  import DotenvPlugin from 'dotenv-webpack';
12
- import {EsbuildPlugin} from 'esbuild-loader';
12
+ import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
13
13
  import FaviconsWebpackPlugin from 'favicons-webpack-plugin';
14
14
  import {existsSync} from 'fs';
15
15
  import {sync as globSync} from 'glob';
@@ -34,6 +34,7 @@ import {merge} from 'webpack-merge';
34
34
  import {WebpackPluginServe} from 'webpack-plugin-serve';
35
35
 
36
36
  import {relativeFilePath, relativeNodePath} from './lib/utils/file.js';
37
+ import {LexConfig} from './lib/LexConfig.js';
37
38
 
38
39
  const {ProgressPlugin, ProvidePlugin} = webpack;
39
40
  const isProduction = process.env.NODE_ENV === 'production';
@@ -53,7 +54,7 @@ const {
53
54
  webpack: webpackCustom
54
55
  } = lexConfig;
55
56
 
56
- const webpackPublicPath = webpackCustom?.publicPath || './src/static';
57
+ const webpackStaticPath = webpackCustom?.staticPath || './src/static';
57
58
 
58
59
  const { publicPath: _, ...webpackConfigFiltered } = webpackCustom || {};
59
60
 
@@ -153,13 +154,13 @@ const imagePath = `${sourceFullPath}/images/`;
153
154
  const fontPath = `${sourceFullPath}/fonts/`;
154
155
  const docPath = `${sourceFullPath}/docs/`;
155
156
 
156
- const publicPathFull = pathResolve(process.cwd(), webpackPublicPath);
157
- if(existsSync(publicPathFull)) {
157
+ const staticPathFull = pathResolve(process.cwd(), webpackStaticPath);
158
+ if(existsSync(staticPathFull)) {
158
159
  staticPaths.push({
159
- from: publicPathFull,
160
+ from: staticPathFull,
160
161
  to: './'
161
162
  });
162
- watchIgnorePaths.push(publicPathFull);
163
+ watchIgnorePaths.push(staticPathFull);
163
164
  }
164
165
 
165
166
  if(existsSync(imagePath)) {
@@ -233,7 +234,7 @@ if(existsSync(`${sourceFullPath}/tsconfig.json`)) {
233
234
  }));
234
235
  }
235
236
 
236
- const esbuildLoaderPath = relativeNodePath('esbuild-loader', dirName);
237
+ const swcLoaderPath = relativeNodePath('swc-loader', dirName);
237
238
  const cssLoaderPath = relativeNodePath('css-loader', dirName);
238
239
  const graphqlLoaderPath = relativeNodePath('graphql-tag/loader', dirName);
239
240
  const htmlLoaderPath = relativeNodePath('html-loader', dirName);
@@ -263,7 +264,7 @@ const alias = aliasKeys.reduce((aliases, key) => {
263
264
  }, {});
264
265
 
265
266
  export default (webpackEnv, webpackOptions) => {
266
- const {bundleAnalyzer, watch, entry: cliEntry, mode: cliMode} = webpackOptions;
267
+ const {bundleAnalyzer, watch, entry: cliEntry, mode: cliMode, port} = webpackOptions;
267
268
  const entryValue = Array.isArray(cliEntry) ? cliEntry[0] : cliEntry;
268
269
 
269
270
  // Debug printout for environment and mode
@@ -322,15 +323,51 @@ export default (webpackEnv, webpackOptions) => {
322
323
  `${sourceFullPath}/**/*.test.ts*`
323
324
  ],
324
325
  include: sourceFullPath,
325
- loader: esbuildLoaderPath,
326
+ loader: swcLoaderPath,
326
327
  options: {
327
- loader: 'tsx',
328
- target: targetEnvironment === 'node' ? 'node16' : 'es2016'
328
+ ...LexConfig.config.swc,
329
+ jsc: {
330
+ ...LexConfig.config.swc?.jsc,
331
+ parser: {
332
+ ...LexConfig.config.swc?.jsc?.parser,
333
+ tsx: false
334
+ }
335
+ }
329
336
  },
330
337
  resolve: {
331
338
  symlinks: true
332
339
  },
333
- test: /\.(ts|tsx|js)$/
340
+ test: /\.(ts|js)$/
341
+ },
342
+ {
343
+ exclude: [
344
+ /node_modules\/(?!(react-native))/,
345
+ `${sourceFullPath}/**/*.test.js*`,
346
+ `${sourceFullPath}/**/*.test.ts*`
347
+ ],
348
+ include: sourceFullPath,
349
+ loader: swcLoaderPath,
350
+ options: {
351
+ ...LexConfig.config.swc,
352
+ jsc: {
353
+ ...LexConfig.config.swc?.jsc,
354
+ parser: {
355
+ ...LexConfig.config.swc?.jsc?.parser,
356
+ tsx: true
357
+ },
358
+ transform: {
359
+ ...LexConfig.config.swc?.jsc?.transform,
360
+ react: {
361
+ ...LexConfig.config.swc?.jsc?.transform?.react,
362
+ runtime: 'automatic'
363
+ }
364
+ }
365
+ }
366
+ },
367
+ resolve: {
368
+ symlinks: true
369
+ },
370
+ test: /\.tsx$/
334
371
  },
335
372
  {
336
373
  exclude: [pathResolve(sourceFullPath, lexConfig.entryHTML)],
@@ -416,13 +453,6 @@ export default (webpackEnv, webpackOptions) => {
416
453
  ]
417
454
  }
418
455
  }
419
- },
420
- {
421
- loader: esbuildLoaderPath,
422
- options: {
423
- loader: 'css',
424
- minify: isProduction
425
- }
426
456
  }
427
457
  ]
428
458
  },
@@ -434,7 +464,7 @@ export default (webpackEnv, webpackOptions) => {
434
464
  },
435
465
  {
436
466
  test: /\.(jpg|jpeg|png|gif|webp|svg|mp4|webm|ogg|mp3|wav|flac|aac)$/,
437
- include: publicPathFull,
467
+ include: staticPathFull,
438
468
  type: 'asset/resource',
439
469
  generator: {
440
470
  filename: '[name].[hash][ext]'
@@ -487,10 +517,7 @@ export default (webpackEnv, webpackOptions) => {
487
517
  isProduction && isWeb
488
518
  ? {
489
519
  minimizer: [
490
- new EsbuildPlugin({
491
- css: true,
492
- target: targetEnvironment
493
- })
520
+ new CssMinimizerPlugin()
494
521
  ],
495
522
  runtimeChunk: 'single',
496
523
  splitChunks: {
@@ -588,7 +615,7 @@ export default (webpackEnv, webpackOptions) => {
588
615
  }
589
616
  },
590
617
  {
591
- from: /\.[css,gif,ico,jpg,json,png,svg]/,
618
+ from: /\\.(css|gif|ico|jpg|json|png|svg)$/,
592
619
  to: ({parsedUrl: {pathname}}) => pathname
593
620
  }
594
621
  ],
@@ -606,7 +633,7 @@ export default (webpackEnv, webpackOptions) => {
606
633
  await next();
607
634
  }),
608
635
  open: process.env.WEBPACK_DEV_OPEN === 'true',
609
- port: 7001,
636
+ port: port || 3000,
610
637
  progress: 'minimal',
611
638
  static: existsSync(outputFullPath) ? [outputFullPath] : [],
612
639
  status: true
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};