@plasmicapp/cli 0.1.335 → 0.1.337

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.
@@ -112,6 +112,24 @@
112
112
  "description": "The file path for the blackbox render module, relative to srcDir.",
113
113
  "type": "string"
114
114
  },
115
+ "rsc": {
116
+ "description": "RSC metadata for this component. The structure of the config changes when this is set:\nrenderModuleFilePath points to the client blackbox render module.\nimportSpec points to the server skeleton file.",
117
+ "properties": {
118
+ "clientModulePath": {
119
+ "description": "The client skeleton file",
120
+ "type": "string"
121
+ },
122
+ "serverModulePath": {
123
+ "description": "The server blackbox render module",
124
+ "type": "string"
125
+ }
126
+ },
127
+ "required": [
128
+ "clientModulePath",
129
+ "serverModulePath"
130
+ ],
131
+ "type": "object"
132
+ },
115
133
  "scheme": {
116
134
  "description": "Code generation scheme used for this component",
117
135
  "enum": [
@@ -36,3 +36,4 @@ export declare function fixAllImportStatements(context: PlasmicContext, baseDir:
36
36
  export declare const tsxToJsx: (code: string) => string;
37
37
  export declare function maybeConvertTsxToJsx(fileName: string, content: string, baseDir: string): string[];
38
38
  export declare const formatScript: (code: string, baseDir: string) => string;
39
+ export declare function fixRscModulesImports(context: PlasmicContext, baseDir: string, fixImportContext: FixImportContext, compConfig: ComponentConfig): Promise<void>;
@@ -206,6 +206,17 @@ export interface ComponentConfig {
206
206
  path?: string;
207
207
  /** Plume type if component is a Plume component */
208
208
  plumeType?: string;
209
+ /**
210
+ * RSC metadata for this component. The structure of the config changes when this is set:
211
+ * renderModuleFilePath points to the client blackbox render module.
212
+ * importSpec points to the server skeleton file.
213
+ */
214
+ rsc?: {
215
+ /** The server blackbox render module */
216
+ serverModulePath: string;
217
+ /** The client skeleton file */
218
+ clientModulePath: string;
219
+ };
209
220
  }
210
221
  export interface IconConfig {
211
222
  /** ID of icon */
@@ -0,0 +1,5 @@
1
+ import { ComponentBundle } from "../api";
2
+ import { ComponentConfig, PlasmicContext, ProjectConfig } from "./config-utils";
3
+ export declare function syncRscFiles(context: PlasmicContext, project: ProjectConfig, bundle: ComponentBundle, compConfig: ComponentConfig, opts: {
4
+ shouldRegenerate: boolean;
5
+ }): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plasmicapp/cli",
3
- "version": "0.1.335",
3
+ "version": "0.1.337",
4
4
  "description": "plasmic cli for syncing local code with Plasmic designs",
5
5
  "engines": {
6
6
  "node": ">=12"
@@ -83,5 +83,5 @@
83
83
  "wrap-ansi": "^7.0.0",
84
84
  "yargs": "^15.4.1"
85
85
  },
86
- "gitHead": "eae6a42f2cfbb2d03d1a66cfbf8fbee5595ae25c"
86
+ "gitHead": "5dbcf9cb4a1be8f4060acbb9e3bdf698e99af7c6"
87
87
  }
@@ -5,10 +5,10 @@ import { logger } from "../deps";
5
5
  import { ComponentUpdateSummary, formatAsLocal } from "../utils/code-utils";
6
6
  import {
7
7
  CONFIG_FILE_NAME,
8
- isPageAwarePlatform,
9
8
  PlasmicContext,
10
9
  ProjectConfig,
11
10
  ProjectLock,
11
+ isPageAwarePlatform,
12
12
  } from "../utils/config-utils";
13
13
  import {
14
14
  defaultPagePath,
@@ -21,6 +21,7 @@ import {
21
21
  writeFileContent,
22
22
  } from "../utils/file-utils";
23
23
  import { assert, ensure } from "../utils/lang-utils";
24
+ import { syncRscFiles } from "../utils/rsc-config";
24
25
  import { confirmWithUser } from "../utils/user-utils";
25
26
 
26
27
  export async function syncProjectComponents(
@@ -231,6 +232,26 @@ export async function syncProjectComponents(
231
232
  }
232
233
  renameFile(context, compConfig.importSpec.modulePath, skeletonPath);
233
234
  compConfig.importSpec.modulePath = skeletonPath;
235
+ if (
236
+ compConfig.rsc?.clientModulePath &&
237
+ fileExists(context, compConfig.rsc.clientModulePath)
238
+ ) {
239
+ const clientModulePath = skeletonPath.replace(
240
+ /\.tsx$/,
241
+ "-client.tsx"
242
+ );
243
+ if (context.cliArgs.quiet !== true) {
244
+ logger.info(
245
+ `Renaming page file: ${compConfig.rsc.clientModulePath} -> ${clientModulePath}\t['${project.projectName}' ${project.projectId}/${id} ${project.version}]`
246
+ );
247
+ }
248
+ renameFile(
249
+ context,
250
+ compConfig.rsc.clientModulePath,
251
+ clientModulePath
252
+ );
253
+ compConfig.rsc.clientModulePath = clientModulePath;
254
+ }
234
255
  }
235
256
 
236
257
  compConfig.plumeType = plumeType;
@@ -304,5 +325,9 @@ export async function syncProjectComponents(
304
325
  );
305
326
  }
306
327
  summary.set(id, { skeletonModuleModified });
328
+
329
+ await syncRscFiles(context, project, bundle, compConfig, {
330
+ shouldRegenerate,
331
+ });
307
332
  }
308
333
  }
@@ -22,11 +22,11 @@ import {
22
22
  } from "../utils/code-utils";
23
23
  import {
24
24
  CONFIG_FILE_NAME,
25
- createProjectConfig,
26
25
  CustomFunctionConfig,
26
+ PlasmicContext,
27
+ createProjectConfig,
27
28
  getOrAddProjectConfig,
28
29
  getOrAddProjectLock,
29
- PlasmicContext,
30
30
  updateConfig,
31
31
  } from "../utils/config-utils";
32
32
  import { HandledError } from "../utils/error";
@@ -38,7 +38,7 @@ import {
38
38
  withBufferedFs,
39
39
  writeFileContent,
40
40
  } from "../utils/file-utils";
41
- import { generateMetadata, getContext, Metadata } from "../utils/get-context";
41
+ import { Metadata, generateMetadata, getContext } from "../utils/get-context";
42
42
  import { printFirstSyncInfo } from "../utils/help";
43
43
  import { ensure, tuple } from "../utils/lang-utils";
44
44
  import {
package/src/api.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import axios, { AxiosError } from "axios";
2
- import socketio, { Socket } from "socket.io-client";
2
+ import socketio from "socket.io-client";
3
3
  import {
4
4
  AuthConfig,
5
5
  CodeConfig,
@@ -33,6 +33,19 @@ export interface ComponentBundle {
33
33
  isPage: boolean;
34
34
  path?: string;
35
35
  plumeType?: string;
36
+ rscMetadata?: {
37
+ // When we generate code for RSC, we generate two additional files per page, those files are used to increment the user experience,
38
+ // it's added one managed server file which is responsible for performing the server actions and one skeleton file which allows the
39
+ // user to add client side logic to the page (the `renderModule` will contain a server component for entry point allowing the user to
40
+ // perform additional server operations).
41
+ pageWrappers: Record<
42
+ "client" | "server",
43
+ {
44
+ module: string;
45
+ fileName: string;
46
+ }
47
+ >;
48
+ };
36
49
  }
37
50
 
38
51
  export interface GlobalVariantBundle {
@@ -440,7 +453,7 @@ export class PlasmicApi {
440
453
  return result.data as ProjectIconsResponse;
441
454
  }
442
455
 
443
- connectSocket(): Socket {
456
+ connectSocket(): ReturnType<typeof socketio> {
444
457
  const socket = socketio(this.studioHost, {
445
458
  path: `/api/v1/socket`,
446
459
  transportOptions: {
@@ -18,9 +18,9 @@ import { logger } from "../deps";
18
18
  import { GLOBAL_SETTINGS } from "../globals";
19
19
  import { HandledError } from "../utils/error";
20
20
  import {
21
+ CONFIG_FILE_NAME,
21
22
  CodeComponentConfig,
22
23
  ComponentConfig,
23
- CONFIG_FILE_NAME,
24
24
  CustomFunctionConfig,
25
25
  GlobalVariantGroupConfig,
26
26
  IconConfig,
@@ -173,6 +173,8 @@ type PlasmicImportType =
173
173
  | "globalContext"
174
174
  | "customFunction"
175
175
  | "splitsProvider"
176
+ | "rscClient"
177
+ | "rscServer"
176
178
  | undefined;
177
179
 
178
180
  const validJsIdentifierChars = [
@@ -201,7 +203,7 @@ function tryParsePlasmicImportSpec(node: ImportDeclaration) {
201
203
  "plasmic-import:\\s+([",
202
204
  ...validJsIdentifierChars,
203
205
  "\\.",
204
- "]+)(?:\\/(component|css|render|globalVariant|projectcss|defaultcss|icon|picture|jsBundle|codeComponent|globalContext|customFunction|splitsProvider))?",
206
+ "]+)(?:\\/(component|css|render|globalVariant|projectcss|defaultcss|icon|picture|jsBundle|codeComponent|globalContext|customFunction|splitsProvider|rscClient|rscServer))?",
205
207
  ].join("")
206
208
  )
207
209
  );
@@ -439,6 +441,46 @@ export function replaceImports(
439
441
  true
440
442
  );
441
443
  stmt.source.value = realPath;
444
+ } else if (type === "rscClient") {
445
+ const compConfig = fixImportContext.components[uuid];
446
+ if (!compConfig) {
447
+ throwMissingReference(context, "component", uuid, fromPath);
448
+ }
449
+ const clientModulePath = compConfig.rsc?.clientModulePath;
450
+ if (!clientModulePath) {
451
+ throw new HandledError(
452
+ `Encountered Plasmic component "${uuid}" that is missing a rscClientModulePath.`
453
+ );
454
+ }
455
+
456
+ stmt.source.value = makeImportPath(
457
+ context,
458
+ fromPath,
459
+ clientModulePath,
460
+ true
461
+ );
462
+ } else if (type === "rscServer") {
463
+ const compConfig = fixImportContext.components[uuid];
464
+ if (!compConfig) {
465
+ throwMissingReference(context, "component", uuid, fromPath);
466
+ }
467
+ const serverModulePath = compConfig.rsc?.serverModulePath;
468
+ if (!serverModulePath) {
469
+ throw new HandledError(
470
+ `Encountered Plasmic component "${uuid}" that is missing a rscServerModulePath.`
471
+ );
472
+ }
473
+
474
+ logger.info(
475
+ `Fixing "rscServer" with "${serverModulePath}" and from "${fromPath}"`
476
+ );
477
+
478
+ stmt.source.value = makeImportPath(
479
+ context,
480
+ fromPath,
481
+ serverModulePath,
482
+ true
483
+ );
442
484
  }
443
485
  });
444
486
 
@@ -569,6 +611,17 @@ export async function fixAllImportStatements(
569
611
  let lastError: any = undefined;
570
612
  for (const project of config.projects) {
571
613
  for (const compConfig of project.components) {
614
+ try {
615
+ await fixRscModulesImports(
616
+ context,
617
+ baseDir,
618
+ fixImportContext,
619
+ compConfig
620
+ );
621
+ } catch (err) {
622
+ lastError = err;
623
+ }
624
+
572
625
  const compSummary = summary?.get(compConfig.id);
573
626
  if (summary && !compSummary) {
574
627
  continue;
@@ -876,3 +929,41 @@ async function fixSplitsProviderImportStatements(
876
929
  }
877
930
  }
878
931
  }
932
+
933
+ export async function fixRscModulesImports(
934
+ context: PlasmicContext,
935
+ baseDir: string,
936
+ fixImportContext: FixImportContext,
937
+ compConfig: ComponentConfig
938
+ ) {
939
+ const errors: any[] = [];
940
+
941
+ for (const modulePath of [
942
+ compConfig.rsc?.clientModulePath,
943
+ compConfig.rsc?.serverModulePath,
944
+ ]) {
945
+ if (!modulePath) {
946
+ continue;
947
+ }
948
+
949
+ try {
950
+ await fixFileImportStatements(
951
+ context,
952
+ modulePath,
953
+ fixImportContext,
954
+ false,
955
+ baseDir
956
+ );
957
+ } catch (err) {
958
+ logger.error(
959
+ `Error encountered while fixing imports for rsc modules ${compConfig.name}: ${err}`
960
+ );
961
+
962
+ errors.push(err);
963
+ }
964
+ }
965
+
966
+ if (errors.length) {
967
+ throw errors[0];
968
+ }
969
+ }
@@ -288,6 +288,18 @@ export interface ComponentConfig {
288
288
 
289
289
  /** Plume type if component is a Plume component */
290
290
  plumeType?: string;
291
+
292
+ /**
293
+ * RSC metadata for this component. The structure of the config changes when this is set:
294
+ * renderModuleFilePath points to the client blackbox render module.
295
+ * importSpec points to the server skeleton file.
296
+ */
297
+ rsc?: {
298
+ /** The server blackbox render module */
299
+ serverModulePath: string;
300
+ /** The client skeleton file */
301
+ clientModulePath: string;
302
+ };
291
303
  }
292
304
 
293
305
  export interface IconConfig {
@@ -463,11 +463,18 @@ export function readFileText(path: string): string {
463
463
  case "create":
464
464
  return ensureString(action.content);
465
465
  case "rename":
466
- return readFileText(action.newPath);
466
+ // eslint-disable-next-line no-restricted-properties
467
+ return fs.readFileSync(path, "utf8");
467
468
  case "delete":
468
469
  throw new HandledError("File does not exists");
469
470
  }
470
471
  }
472
+ // If we are buffering files and the file has been renamed, only the old file path
473
+ // exists in disk, so we need to read the content from the old file path.
474
+ const renamedFilePath = renamedFiles.get(path);
475
+ if (renamedFilePath) {
476
+ return readFileText(renamedFilePath);
477
+ }
471
478
  }
472
479
 
473
480
  // eslint-disable-next-line no-restricted-properties
@@ -503,7 +510,6 @@ export function renameFileBuffered(oldPath: string, newPath: string) {
503
510
  if (renamedFile !== undefined) {
504
511
  oldPath = renamedFile;
505
512
  }
506
-
507
513
  buffer.set(oldPath, { type: "rename", newPath });
508
514
  renamedFiles.set(newPath, oldPath);
509
515
  } else {
@@ -0,0 +1,56 @@
1
+ import { ComponentBundle } from "../api";
2
+ import { ComponentConfig, PlasmicContext, ProjectConfig } from "./config-utils";
3
+ import { defaultResourcePath, writeFileContent } from "./file-utils";
4
+
5
+ export async function syncRscFiles(
6
+ context: PlasmicContext,
7
+ project: ProjectConfig,
8
+ bundle: ComponentBundle,
9
+ compConfig: ComponentConfig,
10
+ opts: {
11
+ shouldRegenerate: boolean;
12
+ }
13
+ ) {
14
+ const rscMetadata = bundle.rscMetadata;
15
+ if (rscMetadata) {
16
+ if (!compConfig.rsc) {
17
+ compConfig.rsc = {
18
+ serverModulePath: "",
19
+ clientModulePath: "",
20
+ };
21
+ }
22
+
23
+ const serverModuleFilePath = defaultResourcePath(
24
+ context,
25
+ project,
26
+ rscMetadata.pageWrappers.server.fileName
27
+ );
28
+ compConfig.rsc.serverModulePath = serverModuleFilePath;
29
+
30
+ await writeFileContent(
31
+ context,
32
+ serverModuleFilePath,
33
+ rscMetadata.pageWrappers.server.module,
34
+ {
35
+ force: true,
36
+ }
37
+ );
38
+
39
+ const clientModuleFilePath = compConfig.importSpec.modulePath.replace(
40
+ /\.tsx$/,
41
+ "-client.tsx"
42
+ );
43
+ compConfig.rsc.clientModulePath = clientModuleFilePath;
44
+
45
+ if (opts.shouldRegenerate) {
46
+ await writeFileContent(
47
+ context,
48
+ clientModuleFilePath,
49
+ rscMetadata.pageWrappers.client.module,
50
+ {
51
+ force: false,
52
+ }
53
+ );
54
+ }
55
+ }
56
+ }