create-lupine 1.0.22 → 1.0.24

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/index.js CHANGED
@@ -6,17 +6,23 @@ import { fileURLToPath } from 'node:url';
6
6
  import crypto from 'node:crypto';
7
7
  import { execSync } from 'node:child_process';
8
8
 
9
- function getLatestVersion(pkgName, fallback) {
10
- try {
11
- const version = execSync(`npm view ${pkgName} version`, {
12
- encoding: 'utf8',
13
- stdio: ['ignore', 'pipe', 'ignore'],
14
- timeout: 3000,
15
- }).trim();
16
- return version ? `^${version}` : fallback;
17
- } catch (e) {
18
- return fallback;
9
+ function getLatestVersion(pkgName, fallback, retries = 2) {
10
+ for (let i = 0; i <= retries; i++) {
11
+ try {
12
+ const version = execSync(`npm view ${pkgName} version`, {
13
+ encoding: 'utf8',
14
+ stdio: ['ignore', 'pipe', 'ignore'],
15
+ timeout: 5000,
16
+ }).trim();
17
+ return version ? `^${version}` : fallback;
18
+ } catch (e) {
19
+ if (i === retries) {
20
+ console.warn(`\x1b[33mWarning: Failed to fetch latest version for ${pkgName}. Using fallback ${fallback}\x1b[0m`);
21
+ return fallback;
22
+ }
23
+ }
19
24
  }
25
+ return fallback;
20
26
  }
21
27
 
22
28
  function generateRandomString(length) {
@@ -289,8 +295,8 @@ async function init() {
289
295
  dev: 'node ./dev/dev-watch --env=.env.development --dev=1 --cmd=start-dev',
290
296
  build: 'node ./dev/dev-watch --env=.env.production --dev=0 --obfuscate=0',
291
297
  'build-mobile': 'node ./dev/dev-watch --env=.env.mobile --dev=0 --mobile=1',
292
- 'start-dev': 'node dist/server_root/server/app-loader.js --env=.env.development',
293
- 'start-production': 'node dist/server_root/server/app-loader.js --env=.env.production',
298
+ 'start-dev': 'node dist/server_root/server/server-loader.js --env=.env.development',
299
+ 'start-production': 'node dist/server_root/server/server-loader.js --env=.env.production',
294
300
  format: 'prettier --write "**/*.{js,json,css,scss,md,html,yaml,ts,jsx,tsx}"',
295
301
  },
296
302
  dependencies: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-lupine",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "description": "Scaffolding tool for Lupine.js projects",
5
5
  "bin": {
6
6
  "create-lupine": "index.js"
@@ -7,7 +7,6 @@ When performing multi-line code refactoring or replacement operations (`replace_
7
7
  - The `StartLine` and `EndLine` range MUST be restricted strictly to the absolute minimum lines you intend to modify or delete.
8
8
  - If you are merely inserting new code (e.g., adding a button or appending logic), target ONLY the immediately preceding line or bracket as your anchor. You are strictly forbidden from wrapping innocent, unmodified surrounding code into the `Replacement` payload. Violating this red line causes severe production accidents!
9
9
 
10
-
11
10
  **SYSTEM ROLE**: You are an expert developer in `lupine.js`, a custom TypeScript full-stack framework.
12
11
 
13
12
  **🛑 CRITICAL WARNINGS 🛑**
@@ -90,7 +89,7 @@ bindGlobalStyle('my-comp-theme', cssTheme, false, true);
90
89
  const css: CssProps = {
91
90
  '.&-element': {
92
91
  backgroundColor: 'var(--my-comp-bg-color)',
93
- }
92
+ },
94
93
  };
95
94
  // Bind your component styles normally
96
95
  bindGlobalStyle('my-comp-main', css);
@@ -182,6 +181,7 @@ Lupine.js provides two main ways to inject component CSS (`css={}` vs `bindGloba
182
181
  **Best for**: Pages, views, or high-level containers that are only rendered once per screen.
183
182
 
184
183
  When you pass `css={css}` to a JSX element, Lupine automatically evaluates it and injects a new `<style>` tag directly wrapping that element.
184
+
185
185
  - **Pros**: Perfect isolation.
186
186
  - **Cons**: If you render 100 items using `css={}`, it will inject 100 identical `<style>` blocks into the DOM, severely bloating the page.
187
187
 
@@ -192,11 +192,15 @@ When you pass `css={css}` to a JSX element, Lupine automatically evaluates it an
192
192
  `bindGlobalStyle`, combined with `getGlobalStylesId`, places the `<style>` block in the `<head>` of the document **exactly once**. All instances of the component share the same CSS class names, but those names are still guaranteed to be collision-free!
193
193
 
194
194
  **How it works seamlessly with `&`**:
195
- 1. Generate an ID based on the `CssProps` content: `const globalCssId = getGlobalStylesId(css);`. (Call this *inside* the component!)
195
+
196
+ 1. Generate an ID based on the `CssProps` content: `const globalCssId = getGlobalStylesId(css);`. (Call this _inside_ the component!)
196
197
  2. Bind the style block globally once: `bindGlobalStyle(globalCssId, css);`
197
198
  3. Assign this ID to the component's `ref` to link the scope: `const ref: RefProps = { globalCssId };` / `<div ref={ref}>`
198
199
  4. Use `class="&-item"` normally. Lupine replaces `&` with the identical `globalCssId` across all instances.
199
200
 
201
+ > [!WARNING]
202
+ > Because `getGlobalStylesId` relies on `getRequestContext()` data to correctly attach and track styles (especially across SSR and interactive client renders), getGlobalStylesId and `bindGlobalStyle` **MUST** be called inside the component function scope. Calling them at the file/module level will result in runtime errors.
203
+
200
204
  ### ⚠️ IMPORTANT: The "Static `CssProps`" Rule
201
205
 
202
206
  Because `bindGlobalStyle` injects your `<style>` tags into the `<head>` globally, your `CssProps` definition **MUST** be entirely static.
@@ -205,7 +209,7 @@ Because `bindGlobalStyle` injects your `<style>` tags into the `<head>` globally
205
209
 
206
210
  ### 🔗 Sharing the same CSS scope (`globalCssId`) among Separated DOMs
207
211
 
208
- If your component divides its logic so that some internal floating DOM elements are rendered dynamically later (e.g. through a function passed to `HtmlVar`) *separated* from the root return statement, the inner DOM will automatically generate a **new, mismatched** CSS ID if not linked. Its internal `class="&-item"` references will break and styles will fail to apply.
212
+ If your component divides its logic so that some internal floating DOM elements are rendered dynamically later (e.g. through a function passed to `HtmlVar`) _separated_ from the root return statement, the inner DOM will automatically generate a **new, mismatched** CSS ID if not linked. Its internal `class="&-item"` references will break and styles will fail to apply.
209
213
 
210
214
  To force separated local DOM partitions to share the exact same `&` CSS Scope as their parent page, explicitly share a globally unique CSS ID using `globalStyleUniqueId()`:
211
215
 
@@ -213,34 +217,70 @@ To force separated local DOM partitions to share the exact same `&` CSS Scope as
213
217
  import { globalStyleUniqueId, HtmlVar, RefProps, CssProps } from 'lupine.components';
214
218
 
215
219
  export const HomePage = () => {
216
- // 1. Generate a manual ID for the container scope beforehand
217
- const cssId = globalStyleUniqueId();
218
-
219
- const listDom = new HtmlVar('');
220
-
221
- const renderList = () => {
222
- // 2. Explicitly bind the inner detached DOM to the parent's globalCssId
223
- listDom.value = (
224
- <div ref={{ globalCssId: cssId }} class="&-bundle-container">
225
- <div class="&-bundle-name">Basic Bundle</div>
226
- </div>
227
- );
228
- };
229
-
230
- const ref: RefProps = {
231
- globalCssId: cssId, // 3. The parent registers the ID as well
232
- onLoad: async () => renderList()
233
- };
234
- const css: CssProps = { '.&-bundle-name': { color: 'red' } };
220
+ // 1. Generate a manual ID for the container scope beforehand
221
+ const cssId = globalStyleUniqueId();
235
222
 
236
- return (
237
- <div css={css} ref={ref}>
238
- {/* 4. The dynamically injected nodes will properly map their &- prefixes */}
239
- {listDom.node}
240
- </div>
223
+ const listDom = new HtmlVar('');
224
+
225
+ const renderList = () => {
226
+ // 2. Explicitly bind the inner detached DOM to the parent's globalCssId
227
+ listDom.value = (
228
+ <div ref={{ globalCssId: cssId }} class='&-bundle-container'>
229
+ <div class='&-bundle-name'>Basic Bundle</div>
230
+ </div>
241
231
  );
232
+ };
233
+
234
+ const ref: RefProps = {
235
+ globalCssId: cssId, // 3. The parent registers the ID as well
236
+ onLoad: async () => renderList(),
237
+ };
238
+ const css: CssProps = { '.&-bundle-name': { color: 'red' } };
239
+
240
+ return (
241
+ <div css={css} ref={ref}>
242
+ {/* 4. The dynamically injected nodes will properly map their &- prefixes */}
243
+ {listDom.node}
244
+ </div>
245
+ );
246
+ };
247
+ ```
248
+
249
+ ### Using `&` on Top-Level Tags
250
+
251
+ The following example illustrates how to correctly use `&` in the `class` of a top-level tag.
252
+
253
+ Generally, you should not need to use `&` classes on the top-level tag because you can reference the top-level tag directly via `ref.current`. For styling, the first-level styles defined directly under your `CssProps` object are automatically applied to the top-level tag (e.g., `color: 'red'` below).
254
+
255
+ However, when there is a special need to use an `&-` class prefix on the top-level tag, you must be careful: **`"&.&-box"`** is the correct syntax. This is because the standalone `&` selector is replaced by both the explicit `gCssId` and the CSS ID automatically generated for this top-level tag.
256
+
257
+ For instance, if `gCssId="g00"` and the auto-generated CSS ID applied by the `ref` is `"l01"`, then `"&.&-box"` compiles to `"g00.g00-box, l01.l01-box"`.
258
+
259
+ Similarly, a nested selector like `"&.&-box .&-item"` will be compiled into `"g00.g00-box .g00-item, l01.l01-box .l01-item"`.
260
+
261
+ _(Alternatively, if you define the class without the `&-` prefix like `class="box"`, you would target it using `"&.box"`)._
262
+
263
+ ```typescript
264
+ export const Component1 = () => {
265
+ const css: CssProps = {
266
+ color: 'red',
267
+ '&.&-box': { fontWeight: 'bold' },
268
+ '&.&-box .&-item': { backgroundColor: 'blue' },
269
+ };
270
+ const gCssId = getGlobalStylesId(css);
271
+ bindGlobalStyle(gCssId, css);
272
+
273
+ const ref: RefProps = {
274
+ globalCssId: gCssId,
275
+ };
276
+ return (
277
+ <div ref={ref} class='&-box'>
278
+ <div class='&-item'>item</div>
279
+ </div>
280
+ );
242
281
  };
243
282
  ```
283
+
244
284
  ---
245
285
 
246
286
  ## 5. Common Patterns ("The Lupine Way")
@@ -295,22 +335,24 @@ const MyPage = () => {
295
335
  );
296
336
  };
297
337
  ```
338
+
298
339
  ### Page Navigation (`initializePage` vs `<a>`)
299
340
 
300
341
  In the Lupine.js system, all standard `<a>` HTML tags are automatically intercepted. If the link points to an internal route, Lupine safely binds it to `_lupineJs.initializePage(href)` behind the scenes to perform a seamless single-page application (SPA) transition without a full browser reload.
301
342
 
302
- When performing imperative or programmatic routing via JavaScript (e.g. clicking a `<button>` or a `div`), **DO NOT** use `window.location.href = '/path'`, as this forces a harsh full-page reload.
343
+ When performing imperative or programmatic routing via JavaScript (e.g. clicking a `<button>` or a `div`), **DO NOT** use `window.location.href = '/path'`, as this forces a harsh full-page reload.
303
344
 
304
345
  Instead, import and use `initializePage`:
346
+
305
347
  ```typescript
306
348
  import { initializePage } from 'lupine.web';
307
349
 
308
350
  const navigate = () => {
309
- // CORRECT: Seamless SPA transition
310
- initializePage('/play/diff01/1');
311
-
312
- // ERROR / ANTI-PATTERN: Forces full browser reload unless explicitly desired
313
- // window.location.href = '/play/diff01/1';
351
+ // CORRECT: Seamless SPA transition
352
+ initializePage('/play/diff01/1');
353
+
354
+ // ERROR / ANTI-PATTERN: Forces full browser reload unless explicitly desired
355
+ // window.location.href = '/play/diff01/1';
314
356
  };
315
357
  ```
316
358
 
@@ -555,42 +597,51 @@ For interactive lists, `createDragUtil()` from `lupine.components` handles compl
555
597
  **DO NOT USE browser native `alert()`, `confirm()`, or `prompt()`**. Instead, use the native `ActionSheet` promises from `lupine.components` for a modern, mobile-friendly overlay experience:
556
598
 
557
599
  1. **Option Selection (`ActionSheetSelectPromise`)** (Replaces `confirm()` or complex choices):
600
+
558
601
  ```typescript
559
602
  import { ActionSheetSelectPromise } from 'lupine.components';
560
-
603
+
561
604
  const index = await ActionSheetSelectPromise({
562
605
  title: 'Delete this saved game?', // Optional
563
606
  options: ['Delete', 'Edit'],
564
607
  cancelButtonText: 'Cancel',
565
608
  });
566
-
567
- if (index === 0) { /* User clicked Delete (Index of options array) */ }
568
- if (index === -1) { /* User clicked Cancel or tapped background */ }
609
+
610
+ if (index === 0) {
611
+ /* User clicked Delete (Index of options array) */
612
+ }
613
+ if (index === -1) {
614
+ /* User clicked Cancel or tapped background */
615
+ }
569
616
  ```
570
617
 
571
618
  2. **Simple Messages (`ActionSheetMessagePromise`)** (Replaces `alert()`):
619
+
572
620
  ```typescript
573
621
  import { ActionSheetMessagePromise } from 'lupine.components';
574
-
622
+
575
623
  await ActionSheetMessagePromise({
576
- title: 'Success', // Optional
624
+ title: 'Success', // Optional
577
625
  message: 'Your profile has been saved.',
578
- closeButtonText: 'OK' // Optional, defaults to a close behavior
626
+ closeButtonText: 'OK', // Optional, defaults to a close behavior
579
627
  });
580
628
  ```
581
629
 
582
630
  3. **User Input (`ActionSheetInputPromise`)** (Replaces `prompt()`):
631
+
583
632
  ```typescript
584
633
  import { ActionSheetInputPromise } from 'lupine.components';
585
-
634
+
586
635
  const value = await ActionSheetInputPromise({
587
636
  title: 'Enter your name',
588
637
  // placeholder: 'Player 1', // Optional
589
638
  confirmButtonText: 'Submit', // Optional
590
- cancelButtonText: 'Cancel' // Optional
639
+ cancelButtonText: 'Cancel', // Optional
591
640
  });
592
-
593
- if (value !== null) { /* User submitted a string */ }
641
+
642
+ if (value !== null) {
643
+ /* User submitted a string */
644
+ }
594
645
  ```
595
646
 
596
647
  4. **Other Available Prompts (Investigate their API via `lupine.components` when needed)**:
@@ -609,10 +660,10 @@ import { backActionHelper } from 'lupine.components';
609
660
 
610
661
  export const MyCloseButton = ({ onClose }) => {
611
662
  return (
612
- <i
613
- class="ifc-icon ma-close"
663
+ <i
664
+ class='ifc-icon ma-close'
614
665
  // Generate a unique ID for the back stack
615
- data-back-action={backActionHelper.genBackActionId()}
666
+ data-back-action={backActionHelper.genBackActionId()}
616
667
  onClick={onClose}
617
668
  ></i>
618
669
  );
@@ -620,8 +671,9 @@ export const MyCloseButton = ({ onClose }) => {
620
671
  ```
621
672
 
622
673
  **How it works**:
674
+
623
675
  - When the hardware back button is pressed, the underlying system automatically queries the DOM for all elements with `[data-back-action^="bb-"]`.
624
676
  - It finds the most recently created component (the top-most overlay) and automatically triggers a `.click()` event on it.
625
- - **Dynamic Mounting vs Static**:
677
+ - **Dynamic Mounting vs Static**:
626
678
  - For components that are injected and removed dynamically (like `<ActionSheet />` or `<FloatWindow />`), simply attaching the property to the React/JSX node is sufficient.
627
679
  - For static components that always remain in the DOM but toggle visibility (like an off-canvas sidebar), you must dynamically add/remove the attribute in Javascript (`el.setAttribute` / `el.removeAttribute`) to prevent the back button from intercepting events when the menu is actually closed.
@@ -1,4 +1,4 @@
1
- import { appLoader } from 'lupine.api/app-loader';
1
+ import { serverLoader } from 'lupine.api/server-loader';
2
2
  import path from 'path';
3
3
 
4
- appLoader.startApp(path.join(__dirname, './index.js'));
4
+ serverLoader.startApp(path.join(__dirname, './index.js'));
@@ -1,81 +1,76 @@
1
- // initApp should be called before any other logics, so need to avoid `export default new Class()`
2
- import * as path from 'path';
3
- import {
4
- CryptoUtils,
5
- HostToPathProps,
6
- appStart,
7
- bindRenderPageFunctions,
8
- getDefaultDbConfig,
9
- getRenderPageFunctions,
10
- loadEnv,
11
- setAccessControlAllowHost,
12
- } from 'lupine.api';
13
- import { fetchData } from './fetch-data';
14
- import { ServerEnvKeys } from './server-env-keys';
15
-
16
- const initAndStartServer = async () => {
17
- setAccessControlAllowHost(['localhost', '127.0.0.1']);
18
-
19
- const envFile = process.argv.find((i) => i.startsWith('--env='))?.substring(6) || '.env';
20
- // it can use "#!import file_name" to import another env file
21
- await loadEnv(envFile);
22
- bindRenderPageFunctions({ fetchData });
23
-
24
- const dbConfig = { ...getDefaultDbConfig() };
25
- const serverRootPath = path.resolve(process.env[ServerEnvKeys.SERVER_ROOT_PATH]!);
26
- const apps = (process.env[ServerEnvKeys.APPS] || '').split(',');
27
- const webRootMap: HostToPathProps[] = [];
28
-
29
- const domainCerts: Record<string, { key: string; cert: string }> = {};
30
- for (const app of apps) {
31
- const appHosts = process.env[`${ServerEnvKeys.DOMAINS}:${app}`] || '';
32
- const dbFilename =
33
- process.env[`${ServerEnvKeys.DB_FILENAME}:${app}`] || process.env[`${ServerEnvKeys.DB_FILENAME}`] || 'sqlite3.db';
34
- webRootMap.push({
35
- appName: app,
36
- hosts: appHosts ? appHosts.split(',') : [],
37
- // web, data, api folders should be created in building process
38
- webPath: path.join(serverRootPath, app + '_web'),
39
- dataPath: path.join(serverRootPath, app + '_data'),
40
- apiPath: path.join(serverRootPath, app + '_api'),
41
- dbType: process.env[`${ServerEnvKeys.DB_TYPE}:${app}`] || process.env[`${ServerEnvKeys.DB_TYPE}`] || 'sqlite',
42
- dbConfig: { ...dbConfig, filename: dbFilename },
43
- });
44
-
45
- const appDomains = appHosts.split(',');
46
- for (const domain of appDomains) {
47
- domainCerts[domain] = {
48
- key: process.env[`${ServerEnvKeys.SSL_KEY_PATH}:${app}`] || '',
49
- cert: process.env[`${ServerEnvKeys.SSL_CRT_PATH}:${app}`] || '',
50
- };
51
- }
52
- }
53
-
54
- const bindIp = process.env[ServerEnvKeys.BIND_IP] || '::';
55
- // 0 to disable http/https server
56
- const httpPort = Number.parseInt(process.env[ServerEnvKeys.HTTP_PORT] || '8080');
57
- const httpsPort = Number.parseInt(process.env[ServerEnvKeys.HTTPS_PORT] || '8443');
58
- const sslKeyPath = process.env[ServerEnvKeys.SSL_KEY_PATH] || '';
59
- const sslCrtPath = process.env[ServerEnvKeys.SSL_CRT_PATH] || '';
60
-
61
- // Can't use log until initApp is called (after AppStart.start)
62
- await appStart.start({
63
- debug: process.env[ServerEnvKeys.NODE_ENV] === 'development',
64
- devToken: CryptoUtils.sha256(process.env['DEV_TOKEN'] || ''),
65
- appEnvFile: envFile,
66
- renderPageFunctions: getRenderPageFunctions(),
67
- apiConfig: {
68
- serverRoot: `${serverRootPath}`,
69
- webHostMap: webRootMap,
70
- },
71
- serverConfig: {
72
- bindIp,
73
- httpPort,
74
- httpsPort,
75
- sslKeyPath,
76
- sslCrtPath,
77
- domainCerts,
78
- },
79
- });
80
- };
81
- initAndStartServer();
1
+ // initApp should be called before any other logics, so need to avoid `export default new Class()`
2
+ import * as path from 'path';
3
+ import {
4
+ CryptoUtils,
5
+ HostToPathProps,
6
+ appStart,
7
+ getDefaultDbConfig,
8
+ loadEnv,
9
+ setAccessControlAllowHost,
10
+ } from 'lupine.api/server';
11
+ import { ServerEnvKeys } from './server-env-keys';
12
+
13
+ const initAndStartServer = async () => {
14
+ setAccessControlAllowHost(['localhost', '127.0.0.1']);
15
+
16
+ const envFile = process.argv.find((i) => i.startsWith('--env='))?.substring(6) || '.env';
17
+ // it can use "#!import file_name" to import another env file
18
+ await loadEnv(envFile);
19
+
20
+ const dbConfig = { ...getDefaultDbConfig() };
21
+ const serverRootPath = path.resolve(process.env[ServerEnvKeys.SERVER_ROOT_PATH]!);
22
+ const apps = (process.env[ServerEnvKeys.APPS] || '').split(',');
23
+ const webRootMap: HostToPathProps[] = [];
24
+
25
+ const domainCerts: Record<string, { key: string; cert: string }> = {};
26
+ for (const app of apps) {
27
+ const appHosts = process.env[`${ServerEnvKeys.DOMAINS}:${app}`] || '';
28
+ const dbFilename =
29
+ process.env[`${ServerEnvKeys.DB_FILENAME}:${app}`] || process.env[`${ServerEnvKeys.DB_FILENAME}`] || 'sqlite3.db';
30
+ webRootMap.push({
31
+ appName: app,
32
+ hosts: appHosts ? appHosts.split(',') : [],
33
+ // web, data, api folders should be created in building process
34
+ webPath: path.join(serverRootPath, app + '_web'),
35
+ dataPath: path.join(serverRootPath, app + '_data'),
36
+ apiPath: path.join(serverRootPath, app + '_api'),
37
+ dbType: process.env[`${ServerEnvKeys.DB_TYPE}:${app}`] || process.env[`${ServerEnvKeys.DB_TYPE}`] || 'sqlite',
38
+ dbConfig: { ...dbConfig, filename: dbFilename },
39
+ });
40
+
41
+ const appDomains = appHosts.split(',');
42
+ for (const domain of appDomains) {
43
+ domainCerts[domain] = {
44
+ key: process.env[`${ServerEnvKeys.SSL_KEY_PATH}:${app}`] || '',
45
+ cert: process.env[`${ServerEnvKeys.SSL_CRT_PATH}:${app}`] || '',
46
+ };
47
+ }
48
+ }
49
+
50
+ const bindIp = process.env[ServerEnvKeys.BIND_IP] || '::';
51
+ // 0 to disable http/https server
52
+ const httpPort = Number.parseInt(process.env[ServerEnvKeys.HTTP_PORT] || '8080');
53
+ const httpsPort = Number.parseInt(process.env[ServerEnvKeys.HTTPS_PORT] || '8443');
54
+ const sslKeyPath = process.env[ServerEnvKeys.SSL_KEY_PATH] || '';
55
+ const sslCrtPath = process.env[ServerEnvKeys.SSL_CRT_PATH] || '';
56
+
57
+ // Can't use log until initApp is called (after AppStart.start)
58
+ await appStart.start({
59
+ debug: process.env[ServerEnvKeys.NODE_ENV] === 'development',
60
+ devToken: CryptoUtils.sha256(process.env['DEV_TOKEN'] || ''),
61
+ appEnvFile: envFile,
62
+ apiConfig: {
63
+ serverRoot: `${serverRootPath}`,
64
+ webHostMap: webRootMap,
65
+ },
66
+ serverConfig: {
67
+ bindIp,
68
+ httpPort,
69
+ httpsPort,
70
+ sslKeyPath,
71
+ sslCrtPath,
72
+ domainCerts,
73
+ },
74
+ });
75
+ };
76
+ initAndStartServer();
@@ -0,0 +1,4 @@
1
+ import { serverLoader } from 'lupine.api/server-loader';
2
+ import path from 'path';
3
+
4
+ serverLoader.startApp(path.join(__dirname, './index.js'));
@@ -66,14 +66,14 @@ const watchServerPlugin = (isDev, npmCmd, httpPort) => {
66
66
  };
67
67
 
68
68
  // watch server code changes
69
- const watchAppLoader = async (isDev, npmCmd, httpPort, serverRootPath) => {
69
+ const watchServerLoader = async (isDev, npmCmd, httpPort, serverRootPath) => {
70
70
  const cmd = isDev ? esbuild.context : esbuild.build;
71
71
  const ctx = await cmd({
72
- entryPoints: ['apps/server/src/app-loader.ts'],
72
+ entryPoints: ['apps/server/src/server-loader.ts'],
73
73
  // outdir: path.join(serverRootPath, 'server'),
74
- outfile: path.join(serverRootPath, 'server', 'app-loader.js'),
74
+ outfile: path.join(serverRootPath, 'server', 'server-loader.js'),
75
75
  platform: 'node',
76
- sourcemap: !!isDev,
76
+ sourcemap: isDev ? 'inline' : false, // inline
77
77
  format: 'cjs',
78
78
  bundle: true,
79
79
  treeShaking: true,
@@ -93,7 +93,7 @@ const watchServer = async (isDev, npmCmd, httpPort, serverRootPath) => {
93
93
  entryPoints: ['apps/server/src/index.ts'],
94
94
  outdir: path.join(serverRootPath, 'server'),
95
95
  platform: 'node',
96
- sourcemap: !!isDev,
96
+ sourcemap: isDev ? 'inline' : false, // inline
97
97
  format: 'cjs',
98
98
  bundle: true,
99
99
  treeShaking: true,
@@ -167,7 +167,7 @@ const watchClient = async (saved, isDev, entryPoints, outbase) => {
167
167
  outbase,
168
168
  // entryNames: '[name]-[hash]',
169
169
  platform: 'browser',
170
- sourcemap: !!isDev, // inline
170
+ sourcemap: isDev ? 'inline' : false, // inline
171
171
  format: 'iife',
172
172
  bundle: true,
173
173
  treeShaking: true,
@@ -209,7 +209,7 @@ const watchApi = async (saved, isDev, entryPoints) => {
209
209
  outdir: saved.outdirApi,
210
210
  // outbase,
211
211
  platform: 'node',
212
- sourcemap: !!isDev, // inline
212
+ sourcemap: isDev ? 'inline' : false, // inline
213
213
  format: 'cjs', // iife, cjs
214
214
  bundle: true,
215
215
  treeShaking: true,
@@ -366,6 +366,6 @@ const start = async () => {
366
366
  }
367
367
 
368
368
  watchServer(isDev, npmCmd, httpPort, serverRootPath);
369
- watchAppLoader(isDev, npmCmd, httpPort, serverRootPath);
369
+ watchServerLoader(isDev, npmCmd, httpPort, serverRootPath);
370
370
  };
371
371
  start();
@@ -1,20 +0,0 @@
1
- import { JsonObject } from 'lupine.api';
2
-
3
- export const fetchData = async (urlWithoutHost: string, postData: string | JsonObject) => {
4
- const url = process.env['API_BASE_URL'] + urlWithoutHost;
5
- console.log('========fetchData', url);
6
-
7
- const option = {
8
- method: postData ? 'POST' : 'GET',
9
- body: postData ? (typeof postData === 'string' ? postData : JSON.stringify(postData)) : undefined,
10
- };
11
- const data = await fetch(url, option);
12
- // const json = await data.json();
13
- const text = await data.text();
14
- try {
15
- const json = JSON.parse(text);
16
- return { json };
17
- } catch (e) {
18
- return { text };
19
- }
20
- };