Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@tobiastengler/create-relay-app

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tobiastengler/create-relay-app - npm Package Compare versions

Comparing version 0.0.7 to 1.0.0

dist/tasks/next/Next_AddTypeHelpers.js

3

dist/arguments/SchemaFileArgument.js
import path from "path";
import { NEXT_SRC_PATH } from "../consts.js";
import { h } from "../utils/index.js";

@@ -45,3 +46,3 @@ import { ArgumentBase } from "./ArgumentBase.js";

if (existingArgs.toolchain === "next") {
srcPath = "./src";
srcPath = NEXT_SRC_PATH;
}

@@ -48,0 +49,0 @@ const filepath = path.join(srcPath, filename);

@@ -0,1 +1,2 @@

import { NEXT_APP_ROOT, APP_ROOT } from "../consts.js";
import { h } from "../utils/index.js";

@@ -36,6 +37,6 @@ import { ArgumentBase } from "./ArgumentBase.js";

if (existingArgs.toolchain === "next") {
return Promise.resolve("./");
return Promise.resolve(NEXT_APP_ROOT);
}
return Promise.resolve("./src");
return Promise.resolve(APP_ROOT);
}
}

@@ -10,3 +10,3 @@ #!/usr/bin/env node

import { getPackageManger, inferPackageManager, } from "./misc/packageManagers/index.js";
import { GenerateArtifactDirectoryTask, GenerateRelayEnvironmentTask, GenerateGraphQlSchemaFileTask, TaskRunner, ConfigureRelayCompilerTask, Cra_AddBabelMacroTypeDefinitionsTask, InstallNpmDependenciesTask, InstallNpmDevDependenciesTask, Vite_ConfigureVitePluginRelayTask, Next_ConfigureNextCompilerTask, Cra_AddRelayEnvironmentProvider, Vite_AddRelayEnvironmentProvider, Next_AddRelayEnvironmentProvider, ConfigureEolOfArtifactsTask, HTTP_ENDPOINT, WEBSOCKET_ENDPOINT, } from "./tasks/index.js";
import { GenerateArtifactDirectoryTask, GenerateRelayEnvironmentTask, GenerateGraphQlSchemaFileTask, TaskRunner, ConfigureRelayCompilerTask, Cra_AddBabelMacroTypeDefinitionsTask, InstallNpmDependenciesTask, InstallNpmDevDependenciesTask, Vite_ConfigureVitePluginRelayTask, Next_ConfigureNextCompilerTask, Cra_AddRelayEnvironmentProvider, Vite_AddRelayEnvironmentProvider, Next_AddRelayEnvironmentProvider, ConfigureEolOfArtifactsTask, HTTP_ENDPOINT, WEBSOCKET_ENDPOINT, Next_AddTypeHelpers, } from "./tasks/index.js";
import { headline, h, importantHeadline, printError } from "./utils/index.js";

@@ -120,2 +120,3 @@ import { ProjectContext } from "./misc/ProjectContext.js";

new Next_ConfigureNextCompilerTask(context),
new Next_AddTypeHelpers(context),
new Next_AddRelayEnvironmentProvider(context),

@@ -171,3 +172,3 @@ ]);

// prettier-ignore
console.log("https://github.com/tobias-tengler/create-relay-app/blob/main/docs/next-server-data-fetching.md");
console.log("https://github.com/tobias-tengler/create-relay-app/blob/main/docs/next-data-fetching.md");
}

@@ -174,0 +175,0 @@ console.log();

export const TS_CONFIG_FILE = "tsconfig.json";
export const PACKAGE_FILE = "package.json";
export const APP_ROOT = "./src";
export const NEXT_APP_ROOT = "./";
export const NEXT_SRC_PATH = "./src";
export const TYPESCRIPT_PACKAGE = "typescript";

@@ -7,2 +10,3 @@ export const BABEL_RELAY_PACKAGE = "babel-plugin-relay";

export const REACT_RELAY_PACKAGE = "react-relay";
export const RELAY_RUNTIME_PACKAGE = "relay-runtime";
export const GRAPHQL_WS_PACKAGE = "graphql-ws";

@@ -9,0 +13,0 @@ export const VITE_RELAY_PACKAGE = "vite-plugin-relay";

import path from "path";
import { RELAY_ENV } from "../consts.js";
import { NEXT_SRC_PATH, RELAY_ENV } from "../consts.js";
export class ProjectContext {

@@ -54,3 +54,3 @@ constructor(env, args, manager, fs) {

if (args.toolchain === "next") {
srcDirectory = "./src";
srcDirectory = NEXT_SRC_PATH;
}

@@ -57,0 +57,0 @@ const filepath = path.join(srcDirectory, filename);

@@ -5,3 +5,3 @@ import traverse from "@babel/traverse";

import { RelativePath } from "../../misc/RelativePath.js";
import { insertNamedImport, parseAst, printAst } from "../../utils/ast.js";
import { insertNamedImport, parseAst, printAst, } from "../../utils/ast.js";
import { h } from "../../utils/cli.js";

@@ -8,0 +8,0 @@ import { TaskBase, TaskSkippedError } from "../TaskBase.js";

@@ -42,6 +42,2 @@ import { TaskBase } from "./TaskBase.js";

}
if (this.context.is("next")) {
// prettier-ignore
b.addLine(`import type { RecordMap } from "relay-runtime/lib/store/RelayStoreTypes";`);
}
}

@@ -159,11 +155,5 @@ // prettier-ignore

export function initRelayEnvironment(initialRecords?: RecordMap) {
export function initRelayEnvironment() {
const environment = relayEnvironment ?? createRelayEnvironment();
// If your page has Next.js data fetching methods that use Relay,
// the initial records will get hydrated here.
if (initialRecords) {
environment.getStore().publish(new RecordSource(initialRecords));
}
// For SSG and SSR always create a new Relay environment.

@@ -183,4 +173,2 @@ if (typeof window === "undefined") {

if (!this.context.args.typescript) {
// Remove Typescript type
initEnv = initEnv.replace("initialRecords?: RecordMap", "initialRecords");
initEnv = initEnv.replace(": Environment | undefined", "");

@@ -187,0 +175,0 @@ }

@@ -15,1 +15,2 @@ export * from "./TaskRunner.js";

export * from "./next/Next_AddRelayEnvironmentProvider.js";
export * from "./next/Next_AddTypeHelpers.js";
import traverse from "@babel/traverse";
import path from "path";
import { REACT_RELAY_PACKAGE, RELAY_ENV_PROVIDER } from "../../consts.js";
import { REACT_RELAY_PACKAGE, RELAY_ENV_PROVIDER, RELAY_RUNTIME_PACKAGE, } from "../../consts.js";
import { RelativePath } from "../../misc/RelativePath.js";
import { insertNamedImport, parseAst, printAst } from "../../utils/ast.js";
import { astToString, insertNamedImport, insertNamedImports, parseAst, prettifyCode, } from "../../utils/ast.js";
import { h } from "../../utils/cli.js";

@@ -10,8 +10,19 @@ import { TaskBase, TaskSkippedError } from "../TaskBase.js";

import { removeExtension, hasRelayProvider, wrapJsxInRelayProvider, } from "../cra/Cra_AddRelayEnvironmentProvider.js";
const envCreation = `
const environment = useMemo(
() => initRelayEnvironment(pageProps.initialRecords),
[pageProps.initialRecords]
);
import { Next_AddTypeHelpers } from "./Next_AddTypeHelpers.js";
const envCreationAndHydration = `
const environment = useMemo(initRelayEnvironment, []);
useEffect(() => {
const store = environment.getStore();
// Hydrate the store.
store.publish(new RecordSource(pageProps.initialRecords));
// Notify any existing subscribers.
store.notify();
}, [environment, pageProps.initialRecords])
`;
const APP_PROPS = "AppProps";
const RELAY_PAGE_PROPS = "RelayPageProps";
export class Next_AddRelayEnvironmentProvider extends TaskBase {

@@ -32,3 +43,2 @@ constructor(context) {

const ast = parseAst(code);
const envCreationAst = parseAst(envCreation).program.body[0];
let providerWrapped = false;

@@ -41,2 +51,3 @@ traverse.default(ast, {

}
const functionReturn = path.parentPath;
const isProviderConfigured = hasRelayProvider(path);

@@ -46,7 +57,33 @@ if (isProviderConfigured) {

}
insertNamedImport(path, "useMemo", "react");
const relativeImportPath = new RelativePath(mainFile.parentDirectory, removeExtension(this.context.relayEnvFile.abs));
insertNamedImport(path, "initRelayEnvironment", relativeImportPath.rel);
// Insert the useMemo creating the environment in the function body.
path.parentPath.insertBefore(envCreationAst);
// We need to modify the type of the _app arguments,
// starting with Next 12.3.
if (this.context.args.typescript) {
// Import RelayPageProps.
const relayTypesPath = Next_AddTypeHelpers.getRelayTypesPath(this.context);
const relayTypesImportPath = new RelativePath(mainFile.parentDirectory, removeExtension(relayTypesPath.abs));
insertNamedImport(path, RELAY_PAGE_PROPS, relayTypesImportPath.rel);
// Change argument of type AppProps to AppProps<RelayPageProps>.
const functionBodyPath = functionReturn.parentPath;
if (!functionBodyPath.isBlockStatement()) {
throw new Error("Expected parentPath to be a block statement.");
}
const functionPath = functionBodyPath.parentPath;
if (!functionPath.isFunctionDeclaration() ||
!t.isFunctionDeclaration(functionPath.node)) {
throw new Error("Expected parentPath to be a function declaration.");
}
const appPropsArg = functionPath.node.params[0];
if (!appPropsArg) {
throw new Error("Expected function to have one argument.");
}
const genericAppProps = t.genericTypeAnnotation(t.identifier(APP_PROPS), t.typeParameterInstantiation([
t.genericTypeAnnotation(t.identifier(RELAY_PAGE_PROPS)),
]));
appPropsArg.typeAnnotation = t.typeAnnotation(genericAppProps);
}
insertNamedImports(path, ["useMemo", "useEffect"], "react");
insertNamedImport(path, "RecordSource", RELAY_RUNTIME_PACKAGE);
const relayEnvImportPath = new RelativePath(mainFile.parentDirectory, removeExtension(this.context.relayEnvFile.abs));
insertNamedImport(path, "initRelayEnvironment", relayEnvImportPath.rel);
functionReturn.addComment("leading", "--MARKER", true);
const envProviderId = t.jsxIdentifier(insertNamedImport(path, RELAY_ENV_PROVIDER, REACT_RELAY_PACKAGE).name);

@@ -61,5 +98,7 @@ wrapJsxInRelayProvider(path, envProviderId, t.identifier("environment"));

}
const updatedCode = printAst(ast, code);
let updatedCode = astToString(ast, code);
updatedCode = updatedCode.replace("//--MARKER", envCreationAndHydration);
updatedCode = prettifyCode(updatedCode);
await this.context.fs.writeToFile(mainFile.abs, updatedCode);
}
}

@@ -11,4 +11,7 @@ import generate from "@babel/generator";

}
export function astToString(ast, oldCode) {
return generate.default(ast, { retainLines: true }, oldCode).code;
}
export function printAst(ast, oldCode) {
const newCode = generate.default(ast, { retainLines: true }, oldCode).code;
const newCode = astToString(ast, oldCode);
return prettifyCode(newCode);

@@ -24,12 +27,39 @@ }

export function insertNamedImport(path, importName, packageName) {
const importIdentifier = t.identifier(importName);
return insertNamedImports(path, [importName], packageName)[0];
}
export function insertNamedImports(path, imports, packageName) {
const program = path.findParent((p) => p.isProgram());
const existingImport = getNamedImport(program, importName, packageName);
if (!!existingImport) {
return importIdentifier;
const identifiers = [];
const missingImports = [];
for (const namedImport of imports) {
const importIdentifier = t.identifier(namedImport);
const existingImport = getNamedImport(program, namedImport, packageName);
if (!!existingImport) {
identifiers.push(importIdentifier);
continue;
}
missingImports.push(namedImport);
}
const importDeclaration = t.importDeclaration([t.importSpecifier(t.cloneNode(importIdentifier), importIdentifier)], t.stringLiteral(packageName));
// Insert import at start of file.
program.node.body.unshift(importDeclaration);
return importIdentifier;
console.log({ imports, missingImports, identifiers });
let importDeclaration;
const isFirstImportFromPackage = missingImports.length === imports.length;
if (isFirstImportFromPackage) {
console.log("create new");
importDeclaration = t.importDeclaration([], t.stringLiteral(packageName));
}
else {
console.log("get existing");
importDeclaration = getImportDeclaration(program, packageName);
}
for (const namedImport of missingImports) {
const importIdentifier = t.identifier(namedImport);
const newImport = t.importSpecifier(t.cloneNode(importIdentifier), importIdentifier);
importDeclaration.specifiers.push(newImport);
identifiers.push(importIdentifier);
}
if (isFirstImportFromPackage) {
// Insert import at start of file.
program.node.body.unshift(importDeclaration);
}
return identifiers;
}

@@ -48,2 +78,5 @@ export function insertDefaultImport(path, importName, packageName) {

}
function getImportDeclaration(path, packageName) {
return path.node.body.find((s) => t.isImportDeclaration(s) && s.source.value === packageName);
}
export function getNamedImport(path, importName, packageName) {

@@ -54,3 +87,3 @@ return path.node.body.find((s) => t.isImportDeclaration(s) &&

}
export function getDefaultImport(path, importName, packageName) {
function getDefaultImport(path, importName, packageName) {
return path.node.body.find((s) => t.isImportDeclaration(s) &&

@@ -57,0 +90,0 @@ s.source.value === packageName &&

{
"name": "@tobiastengler/create-relay-app",
"version": "v0.0.7",
"version": "v1.0.0",
"description": "Easy configuration of Relay for existing projects",

@@ -5,0 +5,0 @@ "homepage": "https://github.com/tobias-tengler/create-relay-app#readme",

@@ -54,3 +54,3 @@ <h1 align="center" style="font-size: 30px;">create-relay-app</h1>

- [Manual steps after running the script](./docs/steps-after-setup.md)
- [Server-side data fetching with Next.js](./docs/next-server-data-fetching.md)
- [Data fetching with Next.js](./docs/next-data-fetching.md)
- [babel-plugin-relay in combination with Create-React-App](./docs/cra-babel-setup.md)
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc