@linktr.ee/linkapp 0.0.37 → 0.0.39

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 (85) hide show
  1. package/dev-server/featured/main.tsx +1 -1
  2. package/dev-server/preview/{preview.tsx → Preview.tsx} +1 -1
  3. package/dev-server/sheet/main.tsx +1 -1
  4. package/dist/cli.js +1 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/add.d.ts.map +1 -1
  7. package/dist/commands/add.js +84 -59
  8. package/dist/commands/add.js.map +1 -1
  9. package/dist/commands/build.d.ts.map +1 -1
  10. package/dist/commands/build.js +66 -84
  11. package/dist/commands/build.js.map +1 -1
  12. package/dist/commands/deploy.d.ts +15 -10
  13. package/dist/commands/deploy.d.ts.map +1 -1
  14. package/dist/commands/deploy.js +26 -199
  15. package/dist/commands/deploy.js.map +1 -1
  16. package/dist/commands/dev.d.ts.map +1 -1
  17. package/dist/commands/dev.js +124 -171
  18. package/dist/commands/dev.js.map +1 -1
  19. package/dist/lib/config/resolve-config-path.d.ts +19 -0
  20. package/dist/lib/config/resolve-config-path.d.ts.map +1 -0
  21. package/dist/lib/config/resolve-config-path.js +54 -0
  22. package/dist/lib/config/resolve-config-path.js.map +1 -0
  23. package/dist/lib/deploy/artifacts.d.ts +21 -0
  24. package/dist/lib/deploy/artifacts.d.ts.map +1 -0
  25. package/dist/lib/deploy/artifacts.js +35 -0
  26. package/dist/lib/deploy/artifacts.js.map +1 -0
  27. package/dist/lib/deploy/confirmation.d.ts +12 -0
  28. package/dist/lib/deploy/confirmation.d.ts.map +1 -0
  29. package/dist/lib/deploy/confirmation.js +30 -0
  30. package/dist/lib/deploy/confirmation.js.map +1 -0
  31. package/dist/lib/deploy/context.d.ts +44 -0
  32. package/dist/lib/deploy/context.d.ts.map +1 -0
  33. package/dist/lib/deploy/context.js +39 -0
  34. package/dist/lib/deploy/context.js.map +1 -0
  35. package/dist/lib/deploy/deploy-output.d.ts +10 -0
  36. package/dist/lib/deploy/deploy-output.d.ts.map +1 -0
  37. package/dist/lib/deploy/deploy-output.js +79 -0
  38. package/dist/lib/deploy/deploy-output.js.map +1 -0
  39. package/dist/lib/deploy/deploy-phases.d.ts +41 -0
  40. package/dist/lib/deploy/deploy-phases.d.ts.map +1 -0
  41. package/dist/lib/deploy/deploy-phases.js +116 -0
  42. package/dist/lib/deploy/deploy-phases.js.map +1 -0
  43. package/dist/lib/deploy/deploy-utils.d.ts +53 -0
  44. package/dist/lib/deploy/deploy-utils.d.ts.map +1 -0
  45. package/dist/lib/deploy/deploy-utils.js +149 -0
  46. package/dist/lib/deploy/deploy-utils.js.map +1 -0
  47. package/dist/lib/deploy/execution.d.ts +24 -0
  48. package/dist/lib/deploy/execution.d.ts.map +1 -0
  49. package/dist/lib/deploy/execution.js +29 -0
  50. package/dist/lib/deploy/execution.js.map +1 -0
  51. package/dist/lib/deploy/output.d.ts +16 -0
  52. package/dist/lib/deploy/output.d.ts.map +1 -0
  53. package/dist/lib/deploy/output.js +115 -0
  54. package/dist/lib/deploy/output.js.map +1 -0
  55. package/dist/lib/deploy/pack-project.js +2 -2
  56. package/dist/lib/deploy/pack-project.js.map +1 -1
  57. package/dist/lib/deploy/preflight.d.ts +9 -0
  58. package/dist/lib/deploy/preflight.d.ts.map +1 -0
  59. package/dist/lib/deploy/preflight.js +59 -0
  60. package/dist/lib/deploy/preflight.js.map +1 -0
  61. package/dist/lib/deploy/validation.d.ts.map +1 -1
  62. package/dist/lib/deploy/validation.js +6 -8
  63. package/dist/lib/deploy/validation.js.map +1 -1
  64. package/dist/lib/utils/constants.d.ts +42 -0
  65. package/dist/lib/utils/constants.d.ts.map +1 -0
  66. package/dist/lib/utils/constants.js +42 -0
  67. package/dist/lib/utils/constants.js.map +1 -0
  68. package/dist/lib/utils/errors.d.ts +49 -0
  69. package/dist/lib/utils/errors.d.ts.map +1 -0
  70. package/dist/lib/utils/errors.js +70 -0
  71. package/dist/lib/utils/errors.js.map +1 -0
  72. package/dist/lib/utils/formatters.d.ts +34 -0
  73. package/dist/lib/utils/formatters.d.ts.map +1 -0
  74. package/dist/lib/utils/formatters.js +59 -0
  75. package/dist/lib/utils/formatters.js.map +1 -0
  76. package/dist/lib/utils/output.d.ts +46 -0
  77. package/dist/lib/utils/output.d.ts.map +1 -0
  78. package/dist/lib/utils/output.js +66 -0
  79. package/dist/lib/utils/output.js.map +1 -0
  80. package/dist/sdk/use-open-popup.d.ts +23 -0
  81. package/dist/sdk/use-open-popup.d.ts.map +1 -0
  82. package/dist/sdk/use-open-popup.js +29 -0
  83. package/dist/sdk/use-open-popup.js.map +1 -0
  84. package/package.json +3 -28
  85. package/runtime/index.html +0 -1
@@ -1,208 +1,35 @@
1
- import pc from 'picocolors';
2
- import * as p from '@clack/prompts';
3
- import { existsSync } from 'node:fs';
4
- import { join } from 'node:path';
5
- import { getAppConfig } from '../lib/auth/config.js';
6
- import { getToken } from '../lib/auth/token-storage.js';
7
- import { validateProject, printValidationResults } from '../lib/deploy/validation.js';
8
- import { packProject } from '../lib/deploy/pack-project.js';
9
- import { uploadAssets, checkLinkAppExists } from '../lib/deploy/upload.js';
10
- import { generateManifestFiles } from '../lib/deploy/generate-manifest-files.js';
11
- import { buildCommand } from './build.js';
12
- const writeLine = (message = '') => {
13
- process.stdout.write(`${message}\n`);
14
- };
1
+ import { initializeDeployment, runPreflightChecks, prepareDeploymentArtifacts, confirmDeployment, executeDeployment, } from '../lib/deploy/deploy-phases.js';
2
+ import { displayDeploymentSuccess, displayDeploymentError, } from '../lib/deploy/deploy-output.js';
3
+ import { DeploymentCancelledError } from '../lib/deploy/deploy-utils.js';
4
+ /**
5
+ * Deploy command - builds and uploads a LinkApp to the Linktree platform.
6
+ *
7
+ * This command orchestrates the entire deployment process:
8
+ * 1. Initialize deployment context (auth, config, LinkApp ID)
9
+ * 2. Run preflight checks (build, validation)
10
+ * 3. Prepare artifacts (manifests, packed files)
11
+ * 4. Confirm deployment with user
12
+ * 5. Execute deployment (upload to API)
13
+ * 6. Display results
14
+ *
15
+ * @param options - Deployment options
16
+ */
15
17
  export async function deployCommand(options) {
16
- const env = options.qa ? 'QA' : 'Production';
17
- const startTime = Date.now();
18
18
  try {
19
- const config = await getAppConfig(options.qa ? 'qa' : 'production');
20
- const projectPath = options.path ?? process.cwd();
21
- // Get LinkApp ID from config (check root first, then .config for backward compatibility)
22
- const rootConfigPath = join(projectPath, 'linkapp.config.ts');
23
- const nestedConfigPath = join(projectPath, '.config', 'linkapp.config.ts');
24
- const configPath = existsSync(rootConfigPath) ? rootConfigPath : nestedConfigPath;
25
- const linkAppId = await getLinkAppId(configPath);
26
- writeLine(pc.bold(pc.cyan(`\n→ Deploying ${linkAppId} to ${env}`)));
27
- writeLine(pc.dim('─'.repeat(50)));
28
- writeLine();
29
- // Check authentication
30
- const accessToken = getToken(config.auth.audience);
31
- if (!accessToken) {
32
- writeLine(pc.red('✗ Not authenticated'));
33
- writeLine(pc.dim(` → Run: ${pc.cyan(`npx @linktr.ee/linkapp login${options.qa ? ' --qa' : ''}`)}`));
34
- writeLine();
35
- process.exit(1);
36
- }
37
- // Run build if needed
38
- if (!options.skipBuild) {
39
- const distPath = join(projectPath, 'dist');
40
- if (!existsSync(distPath)) {
41
- writeLine(pc.bold('Building project...'));
42
- const buildStart = Date.now();
43
- await buildCommand({ sourcemap: false });
44
- const buildTime = ((Date.now() - buildStart) / 1000).toFixed(1);
45
- writeLine(pc.dim(` Completed in ${buildTime}s`));
46
- writeLine();
47
- }
48
- }
49
- // Pre-deployment validation
50
- if (!options.skipChecks) {
51
- writeLine(pc.bold('Pre-deployment checks'));
52
- const validationResult = await validateProject();
53
- printValidationResults(validationResult);
54
- if (!validationResult.success) {
55
- writeLine();
56
- writeLine(pc.red('✗ Validation failed'));
57
- writeLine();
58
- process.exit(1);
59
- }
60
- writeLine();
61
- }
62
- const s = p.spinner();
63
- // Generate manifest files from config
64
- s.start('Generating manifest files');
65
- await generateManifestFiles(projectPath);
66
- s.stop('Manifest files generated');
67
- // Check if LinkApp exists
68
- s.start('Checking LinkApp status');
69
- const apiUrl = options.endpoint ?? `${config.link_types_url}/link-types`;
70
- const exists = await checkLinkAppExists(apiUrl, linkAppId, accessToken);
71
- const action = exists ? 'Updating existing LinkApp' : 'Creating new LinkApp';
72
- s.stop(action);
73
- // Pack project
74
- s.start('Packing project files');
75
- const packedFiles = await packProject({ projectPath });
76
- s.stop(`Packed ${packedFiles.length} ${packedFiles.length === 1 ? 'item' : 'items'}`);
77
- // Show files to upload
78
- writeLine();
79
- writeLine(pc.bold('Files to upload:'));
80
- const filesToShow = packedFiles.slice(0, 8);
81
- for (const file of filesToShow) {
82
- writeLine(pc.dim(` • ${file}`));
83
- }
84
- if (packedFiles.length > 8) {
85
- writeLine(pc.dim(` • ... and ${packedFiles.length - 8} more files`));
86
- }
87
- // Confirm deployment
88
- if (!options.skipConfirm) {
89
- writeLine();
90
- const shouldDeploy = await p.confirm({
91
- message: `Deploy to ${env}?`,
92
- initialValue: true,
93
- });
94
- if (p.isCancel(shouldDeploy) || !shouldDeploy) {
95
- writeLine();
96
- writeLine(pc.yellow('⚠ Deployment cancelled'));
97
- writeLine();
98
- return;
99
- }
100
- }
101
- // Upload
102
- writeLine();
103
- const uploadStart = Date.now();
104
- s.start('Uploading assets');
105
- const result = await uploadAssets({
106
- projectPath,
107
- apiUrl,
108
- linkAppId,
109
- accessToken,
110
- isUpdate: exists,
111
- forceUpdate: options.force,
112
- });
113
- const uploadTime = ((Date.now() - uploadStart) / 1000).toFixed(1);
114
- s.stop(`Assets uploaded (${uploadTime}s)`);
115
- // Show success
116
- const totalTime = ((Date.now() - startTime) / 1000).toFixed(1);
117
- writeLine();
118
- writeLine(pc.dim('─'.repeat(50)));
119
- writeLine(pc.green(pc.bold('\n✓ Deployment successful!')));
120
- writeLine(pc.dim(` Completed in ${totalTime}s`));
121
- writeLine();
122
- writeLine(pc.bold('Details:'));
123
- writeLine(pc.dim(` ID: ${result.linkType.linkTypeId}`));
124
- writeLine(pc.dim(` Status: ${result.linkType.status}`));
125
- // Fix timestamp handling - check if it exists and handle both seconds and milliseconds
126
- if (result.linkType.updatedTimestamp) {
127
- const timestamp = result.linkType.updatedTimestamp;
128
- // If timestamp is in seconds (less than year 2100 in seconds), convert to ms
129
- const timestampMs = timestamp < 10000000000 ? timestamp * 1000 : timestamp;
130
- const date = new Date(timestampMs);
131
- writeLine(pc.dim(` Updated: ${date.toLocaleString()}`));
132
- }
133
- writeLine();
134
- writeLine(pc.bold('Next steps:'));
135
- // Step 1: Build is happening
136
- if (result.build?.id) {
137
- const buildUrl = `https://linkapp-ci.replit.app/?linkTypeId=${result.linkType.linkTypeId}&buildId=${result.build.id}`;
138
- writeLine(pc.cyan(` 1. Building your LinkApp (this may take a few minutes):`));
139
- writeLine(pc.dim(` ${buildUrl}`));
140
- writeLine();
141
- }
142
- // Step 2: Add to page (only after build completes)
143
- const createUrl = options.qa
144
- ? `https://qa.linktr.ee/admin?action=create-link&linkType=${result.linkType.linkTypeId}`
145
- : `https://linktr.ee/admin?action=create-link&linkType=${result.linkType.linkTypeId}`;
146
- writeLine(pc.cyan(` 2. Once the build completes, add it to your page:`));
147
- writeLine(pc.dim(` ${createUrl}`));
148
- writeLine();
19
+ const context = await initializeDeployment(options);
20
+ await runPreflightChecks(context);
21
+ const artifacts = await prepareDeploymentArtifacts(context);
22
+ await confirmDeployment(context, artifacts);
23
+ const result = await executeDeployment(context, artifacts);
24
+ displayDeploymentSuccess(context, result);
149
25
  }
150
26
  catch (error) {
151
- writeLine();
152
- writeLine(pc.dim('─'.repeat(50)));
153
- writeLine(pc.red(pc.bold('\n✗ Deployment failed')));
154
- writeLine();
155
- // Check if this is our structured error with API details
156
- if (error && typeof error === 'object' && 'statusCode' in error && 'messages' in error) {
157
- const structuredError = error;
158
- writeLine(pc.bold('Error Details:'));
159
- writeLine(pc.red(` Status: ${structuredError.statusCode}`));
160
- if (Array.isArray(structuredError.messages) && structuredError.messages.length > 0) {
161
- writeLine();
162
- writeLine(pc.bold(' Validation Errors:'));
163
- for (const msg of structuredError.messages) {
164
- writeLine(pc.red(` • ${msg}`));
165
- }
166
- }
167
- if (structuredError.responseData?.error) {
168
- writeLine();
169
- writeLine(pc.bold(' Error Type:'));
170
- writeLine(pc.red(` ${structuredError.responseData.error}`));
171
- }
172
- }
173
- else if (error instanceof Error) {
174
- writeLine(pc.red(` ${error.message}`));
27
+ if (error instanceof DeploymentCancelledError) {
28
+ displayDeploymentError(error);
29
+ return;
175
30
  }
176
- else {
177
- writeLine(pc.red(` ${String(error)}`));
178
- }
179
- writeLine(); // Empty line
31
+ displayDeploymentError(error);
180
32
  process.exit(1);
181
33
  }
182
34
  }
183
- async function getLinkAppId(configPath) {
184
- // Load the TypeScript config and derive ID from manifest name (kebab-case)
185
- const { createJiti } = await import('jiti');
186
- const jiti = createJiti(import.meta.url, {
187
- interopDefault: true,
188
- moduleCache: false,
189
- });
190
- try {
191
- const config = jiti(configPath);
192
- if (!config?.manifest?.name) {
193
- throw new Error('manifest.name is required in configuration');
194
- }
195
- // Derive ID from name using kebab-case (matches backend behavior)
196
- return config.manifest.name
197
- .toLowerCase()
198
- .replace(/[^a-z0-9]+/g, '-')
199
- .replace(/^-+|-+$/g, ''); // Remove leading/trailing hyphens
200
- }
201
- catch (error) {
202
- if (error instanceof Error && error.message.includes('manifest.name is required')) {
203
- throw error;
204
- }
205
- throw new Error(`Failed to load manifest.name from config: ${error instanceof Error ? error.message : error}`);
206
- }
207
- }
208
35
  //# sourceMappingURL=deploy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAA;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC,MAAM,SAAS,GAAG,CAAC,OAAO,GAAG,EAAE,EAAQ,EAAE;IACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAA;AACtC,CAAC,CAAA;AAYD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAsB;IACxD,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAA;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAE5B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAA;QACnE,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;QAEjD,yFAAyF;QACzF,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAA;QAC7D,MAAM,gBAAgB,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAA;QAC1E,MAAM,UAAU,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,gBAAgB,CAAA;QACjF,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,CAAA;QAEhD,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,iBAAiB,SAAS,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,CAAA;QACnE,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QACjC,SAAS,EAAE,CAAA;QAEX,uBAAuB;QACvB,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAClD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAA;YACxC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,+BAA+B,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;YACpG,SAAS,EAAE,CAAA;YACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;QAED,sBAAsB;QACtB,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;YAC1C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1B,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAA;gBACzC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;gBAC7B,MAAM,YAAY,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAA;gBACxC,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;gBAC/D,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,kBAAkB,SAAS,GAAG,CAAC,CAAC,CAAA;gBACjD,SAAS,EAAE,CAAA;YACb,CAAC;QACH,CAAC;QAED,4BAA4B;QAC5B,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YACxB,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAA;YAC3C,MAAM,gBAAgB,GAAG,MAAM,eAAe,EAAE,CAAA;YAChD,sBAAsB,CAAC,gBAAgB,CAAC,CAAA;YAExC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC;gBAC9B,SAAS,EAAE,CAAA;gBACX,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAA;gBACxC,SAAS,EAAE,CAAA;gBACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,SAAS,EAAE,CAAA;QACb,CAAC;QAED,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAA;QAErB,sCAAsC;QACtC,CAAC,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAA;QACpC,MAAM,qBAAqB,CAAC,WAAW,CAAC,CAAA;QACxC,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;QAElC,0BAA0B;QAC1B,CAAC,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAA;QAClC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,IAAI,GAAG,MAAM,CAAC,cAAc,aAAa,CAAA;QACxE,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,CAAC,CAAA;QAEvE,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,sBAAsB,CAAA;QAC5E,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAEd,eAAe;QACf,CAAC,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;QAChC,MAAM,WAAW,GAAG,MAAM,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC,CAAA;QACtD,CAAC,CAAC,IAAI,CAAC,UAAU,WAAW,CAAC,MAAM,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAA;QAErF,uBAAuB;QACvB,SAAS,EAAE,CAAA;QACX,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAA;QACtC,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC3C,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAA;QAClC,CAAC;QACD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,eAAe,WAAW,CAAC,MAAM,GAAG,CAAC,aAAa,CAAC,CAAC,CAAA;QACvE,CAAC;QAED,qBAAqB;QACrB,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YACzB,SAAS,EAAE,CAAA;YACX,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,OAAO,CAAC;gBACnC,OAAO,EAAE,aAAa,GAAG,GAAG;gBAC5B,YAAY,EAAE,IAAI;aACnB,CAAC,CAAA;YAEF,IAAI,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;gBAC9C,SAAS,EAAE,CAAA;gBACX,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAA;gBAC9C,SAAS,EAAE,CAAA;gBACX,OAAM;YACR,CAAC;QACH,CAAC;QAED,SAAS;QACT,SAAS,EAAE,CAAA;QACX,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAC9B,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;QAC3B,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC;YAChC,WAAW;YACX,MAAM;YACN,SAAS;YACT,WAAW;YACX,QAAQ,EAAE,MAAM;YAChB,WAAW,EAAE,OAAO,CAAC,KAAK;SAC3B,CAAC,CAAA;QACF,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QACjE,CAAC,CAAC,IAAI,CAAC,oBAAoB,UAAU,IAAI,CAAC,CAAA;QAE1C,eAAe;QACf,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QAC9D,SAAS,EAAE,CAAA;QACX,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QACjC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC,CAAC,CAAA;QAC1D,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,kBAAkB,SAAS,GAAG,CAAC,CAAC,CAAA;QACjD,SAAS,EAAE,CAAA;QAEX,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAA;QAC9B,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;QAC7D,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QAEzD,uFAAuF;QACvF,IAAI,MAAM,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC;YACrC,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAA;YAClD,6EAA6E;YAC7E,MAAM,WAAW,GAAG,SAAS,GAAG,WAAW,CAAC,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;YAC1E,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC,CAAA;YAClC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,CAAA;QAC1D,CAAC;QAED,SAAS,EAAE,CAAA;QACX,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAA;QAEjC,6BAA6B;QAC7B,IAAI,MAAM,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC;YACrB,MAAM,QAAQ,GAAG,6CAA6C,MAAM,CAAC,QAAQ,CAAC,UAAU,YAAY,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAA;YAErH,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC,CAAA;YAC/E,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,QAAQ,EAAE,CAAC,CAAC,CAAA;YACrC,SAAS,EAAE,CAAA;QACb,CAAC;QAED,mDAAmD;QACnD,MAAM,SAAS,GAAG,OAAO,CAAC,EAAE;YAC1B,CAAC,CAAC,0DAA0D,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE;YACxF,CAAC,CAAC,uDAAuD,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAA;QAEvF,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC,CAAA;QACzE,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,SAAS,EAAE,CAAC,CAAC,CAAA;QACtC,SAAS,EAAE,CAAA;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,SAAS,EAAE,CAAA;QACX,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QACjC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAA;QACnD,SAAS,EAAE,CAAA;QAEX,yDAAyD;QACzD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,YAAY,IAAI,KAAK,IAAI,UAAU,IAAI,KAAK,EAAE,CAAC;YACvF,MAAM,eAAe,GAAG,KAAY,CAAA;YACpC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAA;YACpC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,aAAa,eAAe,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;YAE5D,IAAI,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,IAAI,eAAe,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnF,SAAS,EAAE,CAAA;gBACX,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAA;gBAC1C,KAAK,MAAM,GAAG,IAAI,eAAe,CAAC,QAAQ,EAAE,CAAC;oBAC3C,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC,CAAA;gBACnC,CAAC;YACH,CAAC;YAED,IAAI,eAAe,CAAC,YAAY,EAAE,KAAK,EAAE,CAAC;gBACxC,SAAS,EAAE,CAAA;gBACX,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAA;gBACnC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,eAAe,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;YAChE,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAClC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;QACzC,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAA;QACzC,CAAC;QAED,SAAS,EAAE,CAAA,CAAC,aAAa;QACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,UAAkB;IAC5C,2EAA2E;IAC3E,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAA;IAC3C,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;QACvC,cAAc,EAAE,IAAI;QACpB,WAAW,EAAE,KAAK;KACnB,CAAC,CAAA;IAEF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,CAAA;QAE/B,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;QAC/D,CAAC;QAED,kEAAkE;QAClE,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI;aACxB,WAAW,EAAE;aACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;aAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA,CAAC,kCAAkC;IAC/D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC,EAAE,CAAC;YAClF,MAAM,KAAK,CAAA;QACb,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,6CAA6C,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAA;IAChH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,0BAA0B,EAC1B,iBAAiB,EACjB,iBAAiB,GAElB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EACL,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AAIxE;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAsB;IACxD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAA;QACnD,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAA;QACjC,MAAM,SAAS,GAAG,MAAM,0BAA0B,CAAC,OAAO,CAAC,CAAA;QAC3D,MAAM,iBAAiB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QAC3C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QAC1D,wBAAwB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,wBAAwB,EAAE,CAAC;YAC9C,sBAAsB,CAAC,KAAK,CAAC,CAAA;YAC7B,OAAM;QACR,CAAC;QACD,sBAAsB,CAAC,KAAK,CAAC,CAAA;QAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAoBA,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAkXD,wBAAsB,UAAU,CAAC,OAAO,EAAE,UAAU,iBAsSnD"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAmBA,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAmSD,wBAAsB,UAAU,CAAC,OAAO,EAAE,UAAU,iBAsUnD"}
@@ -14,107 +14,35 @@ const writeLine = (message = '') => {
14
14
  const __filename = fileURLToPath(import.meta.url);
15
15
  const __dirname = dirname(__filename);
16
16
  /**
17
- * Creates an Rsbuild plugin that watches linkapp.config.ts for changes
18
- * and triggers a full page reload when the config is updated
17
+ * Watches linkapp.config.ts for changes and triggers server restart.
18
+ * Based on Rsbuild's watchFilesForRestart implementation.
19
19
  */
20
- function createConfigWatcherPlugin(userProjectPath) {
21
- const configCandidates = [
22
- join(userProjectPath, 'linkapp.config.ts'),
23
- join(userProjectPath, '.config', 'linkapp.config.ts'),
24
- ];
25
- const handleConfigReload = (server) => {
26
- writeLine(pc.cyan(' ○ linkapp.config.ts changed, reloading...'));
27
- try {
28
- loadConfig(userProjectPath);
29
- server.sockWrite('static-changed');
30
- writeLine(pc.green(' ✓ Config reloaded'));
31
- }
32
- catch (error) {
33
- writeLine(pc.red(' ✗ Failed to reload config'));
34
- writeLine(pc.dim(` ${error instanceof Error ? error.message : error}`));
35
- }
36
- };
20
+ function createConfigWatcherPlugin(userProjectPath, onConfigChange) {
37
21
  return {
38
- name: 'linkapp-config-watcher',
22
+ name: 'linkapp:config-watcher',
39
23
  setup(api) {
40
- let watchers = [];
41
- const pendingTimers = new Map();
42
- const disposeWatchers = async () => {
43
- for (const watcher of watchers) {
44
- try {
45
- await watcher.close();
46
- }
47
- catch (error) {
48
- writeLine(pc.red(' ✗ Failed to close config watcher'));
49
- writeLine(pc.dim(` ${error instanceof Error ? error.message : error}`));
50
- }
51
- }
52
- watchers = [];
53
- for (const timeout of pendingTimers.values()) {
54
- clearTimeout(timeout);
55
- }
56
- pendingTimers.clear();
57
- };
58
- api.onBeforeStartDevServer(async ({ server }) => {
59
- await disposeWatchers();
60
- const filesToWatch = configCandidates.filter((candidatePath) => existsSync(candidatePath));
61
- if (filesToWatch.length === 0) {
24
+ let watcher;
25
+ api.onBeforeStartDevServer(async () => {
26
+ const configPaths = [
27
+ resolve(userProjectPath, 'linkapp.config.ts'),
28
+ resolve(userProjectPath, '.config', 'linkapp.config.ts'),
29
+ ].filter((path) => existsSync(path));
30
+ if (configPaths.length === 0)
62
31
  return;
63
- }
64
- const scheduleReload = (targetPath) => {
65
- const normalizedPath = targetPath.toString();
66
- const existingTimeout = pendingTimers.get(normalizedPath);
67
- if (existingTimeout) {
68
- clearTimeout(existingTimeout);
69
- }
70
- const timeout = setTimeout(() => {
71
- pendingTimers.delete(normalizedPath);
72
- handleConfigReload(server);
73
- }, 120);
74
- pendingTimers.set(normalizedPath, timeout);
75
- };
76
- try {
77
- const watcher = chokidar.watch(filesToWatch, {
78
- ignoreInitial: true,
79
- awaitWriteFinish: {
80
- stabilityThreshold: 200,
81
- pollInterval: 50,
82
- },
83
- });
84
- watcher.on('all', (event, changedPath) => {
85
- if (!changedPath) {
86
- return;
87
- }
88
- const normalizedChangedPath = changedPath.toString();
89
- if (!configCandidates.includes(normalizedChangedPath)) {
90
- return;
91
- }
92
- switch (event) {
93
- case 'add':
94
- case 'change':
95
- case 'unlink':
96
- scheduleReload(normalizedChangedPath);
97
- break;
98
- default:
99
- break;
100
- }
101
- });
102
- watcher.on('error', (error) => {
103
- writeLine(pc.red(' ✗ Config watcher encountered an error'));
104
- writeLine(pc.dim(` ${error instanceof Error ? error.message : error}`));
105
- });
106
- watchers.push(watcher);
107
- }
108
- catch (error) {
109
- writeLine(pc.red(' ✗ Failed to watch config file'));
110
- writeLine(pc.dim(` ${error instanceof Error ? error.message : error}`));
111
- }
112
- return async () => {
113
- await disposeWatchers();
32
+ watcher = chokidar.watch(configPaths, {
33
+ ignoreInitial: true,
34
+ ignorePermissionErrors: true,
35
+ });
36
+ const onChange = async (filePath) => {
37
+ writeLine(pc.cyan(`\n ○ ${relative(userProjectPath, filePath)} changed, restarting dev server...\n`));
38
+ await onConfigChange();
114
39
  };
40
+ watcher.on('change', onChange);
41
+ watcher.on('add', onChange);
42
+ watcher.on('unlink', onChange);
115
43
  });
116
44
  api.onCloseDevServer(async () => {
117
- await disposeWatchers();
45
+ await watcher?.close();
118
46
  });
119
47
  },
120
48
  };
@@ -378,18 +306,26 @@ export async function devCommand(options) {
378
306
  const featuredEntryPath = join(linkappDir, 'dev-featured-main.tsx');
379
307
  writeFileSync(sheetEntryPath, generateSheetEntryPoint(devServerPath), 'utf-8');
380
308
  writeFileSync(featuredEntryPath, generateFeaturedEntryPoint(devServerPath, hasFeaturedCarousel), 'utf-8');
381
- // Load config and extract preview_props and settings
382
- let previewProps = {};
383
- let settingsConfig = {};
384
- try {
385
- const config = loadConfig(userProjectPath);
386
- previewProps = config.preview_props || {};
387
- settingsConfig = config.settings || {};
388
- }
389
- catch (error) {
390
- writeLine(pc.yellow('⚠ Warning: Could not load config, using default preview props'));
391
- writeLine(pc.dim(` ${error instanceof Error ? error.message : error}`));
392
- }
309
+ // Helper to load config (called on initial start and on config changes)
310
+ const loadProjectConfig = () => {
311
+ try {
312
+ const config = loadConfig(userProjectPath);
313
+ return {
314
+ previewProps: config.preview_props || {},
315
+ settingsConfig: config.settings || {},
316
+ };
317
+ }
318
+ catch (error) {
319
+ writeLine(pc.yellow('⚠ Warning: Could not load config, using default preview props'));
320
+ writeLine(pc.dim(` ${error instanceof Error ? error.message : error}`));
321
+ return {
322
+ previewProps: {},
323
+ settingsConfig: {},
324
+ };
325
+ }
326
+ };
327
+ // Load config initially
328
+ let { previewProps, settingsConfig } = loadProjectConfig();
393
329
  const requestedPort = options.port || 3000;
394
330
  const availablePort = await detect(requestedPort);
395
331
  // Show warning if the requested port was occupied
@@ -451,77 +387,85 @@ export async function devCommand(options) {
451
387
  process.stdin.pause();
452
388
  };
453
389
  };
454
- // Create Rsbuild server - inject preview props directly via define
455
- const rsbuild = await createRsbuild({
456
- rsbuildConfig: {
457
- dev: {
458
- progressBar: false,
459
- },
460
- plugins: [
461
- pluginReact(),
462
- createConfigWatcherPlugin(userProjectPath),
463
- createPublicDirPlugin(userPublicDir),
464
- ],
465
- source: {
466
- entry: {
467
- index: resolve(devServerPath, 'preview/main.tsx'),
468
- sheet: sheetEntryPath,
469
- featured: featuredEntryPath,
390
+ // Callback wrapper for config watcher (will be assigned after restartServer is defined)
391
+ let restartCallback;
392
+ // Helper to create Rsbuild instance with current config values
393
+ const createRsbuildInstance = async () => {
394
+ return await createRsbuild({
395
+ rsbuildConfig: {
396
+ dev: {
397
+ progressBar: false,
470
398
  },
471
- define: {
472
- __PREVIEW_PROPS__: JSON.stringify(previewProps),
473
- __SETTINGS_CONFIG__: JSON.stringify(settingsConfig),
474
- },
475
- },
476
- resolve: {
477
- alias: {
478
- '@': userProjectPath,
399
+ plugins: [
400
+ pluginReact(),
401
+ createPublicDirPlugin(userPublicDir),
402
+ createConfigWatcherPlugin(userProjectPath, async () => {
403
+ await restartCallback?.();
404
+ }),
405
+ ],
406
+ source: {
407
+ entry: {
408
+ index: resolve(devServerPath, 'preview/main.tsx'),
409
+ sheet: sheetEntryPath,
410
+ featured: featuredEntryPath,
411
+ },
412
+ define: {
413
+ __PREVIEW_PROPS__: JSON.stringify(previewProps),
414
+ __SETTINGS_CONFIG__: JSON.stringify(settingsConfig),
415
+ },
479
416
  },
480
- dedupe: ['react', 'react-dom'],
481
- },
482
- html: {
483
- template({ entryName }) {
484
- const templates = {
485
- index: resolve(devServerPath, 'index.html'),
486
- sheet: resolve(devServerPath, 'sheet.html'),
487
- featured: resolve(devServerPath, 'featured.html'),
488
- };
489
- return templates[entryName] || resolve(devServerPath, 'index.html');
417
+ resolve: {
418
+ alias: {
419
+ '@': userProjectPath,
420
+ },
421
+ dedupe: ['react', 'react-dom'],
490
422
  },
491
- },
492
- server: {
493
- port,
494
- host: 'localhost',
495
- open: false,
496
- strictPort: false,
497
- printUrls: false,
498
- publicDir: {
499
- name: userPublicDir,
500
- watch: true,
423
+ html: {
424
+ template({ entryName }) {
425
+ const templates = {
426
+ index: resolve(devServerPath, 'index.html'),
427
+ sheet: resolve(devServerPath, 'sheet.html'),
428
+ featured: resolve(devServerPath, 'featured.html'),
429
+ };
430
+ return templates[entryName] || resolve(devServerPath, 'index.html');
431
+ },
501
432
  },
502
- },
503
- tools: {
504
- postcss: (opts) => {
505
- // Load PostCSS config from dev-server directory
506
- opts.postcssOptions = {
507
- ...opts.postcssOptions,
508
- config: resolve(devServerPath, 'postcss.config.mjs'),
509
- };
510
- return opts;
433
+ server: {
434
+ port,
435
+ host: 'localhost',
436
+ open: false,
437
+ strictPort: false,
438
+ printUrls: false,
439
+ publicDir: {
440
+ name: userPublicDir,
441
+ watch: true,
442
+ },
511
443
  },
512
- rspack: (config) => {
513
- // Add linkapp package's node_modules to module resolution paths
514
- // This allows dev-server files to import dependencies from @linktr.ee/linkapp
515
- config.resolve = config.resolve || {};
516
- config.resolve.modules = [
517
- resolve(__dirname, '../../node_modules'),
518
- 'node_modules',
519
- ];
520
- return config;
444
+ tools: {
445
+ postcss: (opts) => {
446
+ // Load PostCSS config from dev-server directory
447
+ opts.postcssOptions = {
448
+ ...opts.postcssOptions,
449
+ config: resolve(devServerPath, 'postcss.config.mjs'),
450
+ };
451
+ return opts;
452
+ },
453
+ rspack: (config) => {
454
+ // Add linkapp package's node_modules to module resolution paths
455
+ // This allows dev-server files to import dependencies from @linktr.ee/linkapp
456
+ config.resolve = config.resolve || {};
457
+ config.resolve.modules = [
458
+ resolve(__dirname, '../../node_modules'),
459
+ 'node_modules',
460
+ ];
461
+ return config;
462
+ },
521
463
  },
522
464
  },
523
- },
524
- });
465
+ });
466
+ };
467
+ // Create initial Rsbuild instance
468
+ let rsbuild = await createRsbuildInstance();
525
469
  let currentServer;
526
470
  let cleanupShortcuts;
527
471
  let isRestarting = false;
@@ -540,10 +484,17 @@ export async function devCommand(options) {
540
484
  return;
541
485
  }
542
486
  isRestarting = true;
543
- writeLine();
544
487
  writeLine(pc.cyan(' ↻ Restarting dev server...'));
545
488
  try {
489
+ // Close current server
546
490
  await currentServer.server.close();
491
+ // Reload config to get fresh preview props
492
+ const freshConfig = loadProjectConfig();
493
+ previewProps = freshConfig.previewProps;
494
+ settingsConfig = freshConfig.settingsConfig;
495
+ // Recreate Rsbuild instance with fresh config
496
+ rsbuild = await createRsbuildInstance();
497
+ // Start new server
547
498
  const restartStart = Date.now();
548
499
  await startServer(restartStart);
549
500
  }
@@ -588,6 +539,8 @@ export async function devCommand(options) {
588
539
  process.exit(0);
589
540
  }
590
541
  };
542
+ // Assign restart callback for config watcher
543
+ restartCallback = restartServer;
591
544
  await startServer(startTime);
592
545
  cleanupShortcuts = setupKeyboardShortcuts({
593
546
  restart: restartServer,